<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blogs on KendraLittle.com</title><link>https://kendralittle.com/blog/</link><description>Recent content in Blogs on KendraLittle.com</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>help@KendraLittle.com (Kendra Little)</managingEditor><webMaster>help@KendraLittle.com (Kendra Little)</webMaster><lastBuildDate>Mon, 09 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://kendralittle.com/blog/rss.xml" rel="self" type="application/rss+xml"/><item><title>Bad News, DBAs, We Are All Developers Now</title><link>https://kendralittle.com/2026/02/09/bad-news-dbas-we-are-all-developers-now/</link><pubDate>Mon, 09 Feb 2026 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2026/02/09/bad-news-dbas-we-are-all-developers-now/</guid><description>&lt;p&gt;I sometimes joke that I&amp;rsquo;m a Junior Developer and a Principal Database Administrator, which is why I have a Staff level title. I&amp;rsquo;m not sure it&amp;rsquo;s a joke anymore, though.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m still an OLTP database specialist, but increasingly I&amp;rsquo;m also a programmer who commits code in multiple languages. I own pull requests that I ship in a release process, following all the same rules and patterns as other developers. My PRs feature unit tests, integration tests, feature flags, the whole shebang.&lt;/p&gt;
&lt;p&gt;Tech roles, including DBA roles, are changing rapidly due to AI coding advances. Don&amp;rsquo;t use AI to write production SQL code without incredibly heavy review and revisions, but do use it to accelerate shipping your improvements to SQL code.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/we-are-all-developers-now.jpeg" width="250"&gt;
&lt;/figure&gt;
&lt;h2 id="a-pivotal-hackathon"&gt;A Pivotal Hackathon&lt;/h2&gt;
&lt;p&gt;This shift happened pretty suddenly for me. We had a hackathon at work where some members of our platform team helped everyone who didn&amp;rsquo;t have a working local dev environment get one running &amp;ndash; people managers, Product Managers, everyone. I got things working in just over an hour with the help of the team and a couple of AI agents. I was shocked at how much I could suddenly do, see, and learn in my local environment.&lt;/p&gt;
&lt;p&gt;This experience made me realize there was nothing standing in the way of me owning all my code changes completely, even the portions that aren&amp;rsquo;t SQL code. In that hour, I could see the full stack, understand how my SQL changes connected to the application layer, and make changes across both. It was a revelation.&lt;/p&gt;
&lt;p&gt;Before the hackathon, I would identify a problem, identify a change in code or an index, then work with a developer on the application code changes, testing, and feature flag work to get the change shipped. This was always a partnership, which was good. This built relationships with developers. But it was often slow: teams have lots of priorities to manage.&lt;/p&gt;
&lt;p&gt;In some ways I worried that owning my own changes fully would mean more separation from dev teams. But actually, shifting things to own my own changes and participating more actively in the code review process on both sides has increased the amount of collaborative time I spend with software engineers.&lt;/p&gt;
&lt;p&gt;After the hackathon, I realized I can own nearly all of the performance tuning changes I work on end-to-end. I am increasingly proficient at reading and analyzing C# and understanding the common patterns we use in our codebase, and I learn more with every PR both from AI agent feedback as well as from teammates in code review.&lt;/p&gt;
&lt;h2 id="help-from-teammates"&gt;Help from Teammates&lt;/h2&gt;
&lt;p&gt;For the first couple of PRs that I managed on my own, it was helpful to have a partner on the app dev side to help provide feedback early about my code changes. I was overcomplicating some things, and feedback helped me learn to prompt AI agents better to follow our patterns and practices more simply.&lt;/p&gt;
&lt;p&gt;Honestly, the hardest part was getting over my own worries that I was going to mess something up. But practices such as feature flagging and testing, along with my teammates&amp;rsquo; code reviews and careful testing both in my local dev environment and load testing environments, helped me gain more confidence in my ability to ship more significant changes and refactor more complex code.&lt;/p&gt;
&lt;p&gt;In the past I&amp;rsquo;ve largely focused on making the most impactful changes I can while taking on the smallest amount of risk where possible. This is still a very useful approach, but sometimes you need to take on a larger problem where there is a high amount of risk that you need to minimize as much as possible: I&amp;rsquo;m now much better equipped to do that on my own.&lt;/p&gt;
&lt;h2 id="benefits-of-owning-changes-end-to-end"&gt;Benefits of Owning Changes End to End&lt;/h2&gt;
&lt;p&gt;I really like shipping my own changes. When I own the code changes, I can iterate faster. I can identify the issue, write the fix, test it, and ship it without waiting for someone else&amp;rsquo;s schedule to align with mine. This speed matters when you&amp;rsquo;re dealing with performance problems that are impacting customers.&lt;/p&gt;
&lt;p&gt;I have increased understanding of the user experience and how slow or failing code impacts customers. I&amp;rsquo;m learning more about the developer experience of writing features with SQL code, and what&amp;rsquo;s easy to do versus hard to do. I can see the full picture, from the database query to the application code to how it impacts the user.&lt;/p&gt;
&lt;p&gt;The partnership with developers was valuable, and I still have that. But now I can move faster when I need to, and the collaboration happens more through code review on both sides rather than through handoffs.&lt;/p&gt;
&lt;h2 id="ai-for-app-code-following-patterns-works-extremely-well"&gt;AI for App Code: Following Patterns Works Extremely Well&lt;/h2&gt;
&lt;p&gt;This is where AI really shines for database professionals who are expanding their development skills. AI is quite well trained at generating code with languages like C# and Python, which makes owning all my code changes practical.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve found a few things that work well when using AI with app code. Instruct the AI to look at patterns in the repo. Provide example pull requests for reference on patterns to follow. Work with teammates to continuously improve instructions for agents to help developers with common workflows.&lt;/p&gt;
&lt;p&gt;AI also helps me considerably in managing and using development environments. Dev environments are increasingly complex with Kubernetes and lots of orchestration. AI helps me understand each environment, troubleshoot failures, and learn how to effectively test with it. It helps me identify how to click-test or script-test code changes, which helps me identify where SQL is called from on the application side and ensure that testing coverage reaches them all.&lt;/p&gt;
&lt;h2 id="where-ai-is-terrible-for-sql-code"&gt;Where AI is Terrible for SQL Code&lt;/h2&gt;
&lt;p&gt;There are some problems with having AI generate SQL code and shipping it without heavy review and testing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Syntax often doesn&amp;rsquo;t work.&lt;/strong&gt; AI tooling typically doesn&amp;rsquo;t have a sandbox environment to validate the specific dialect of SQL code you&amp;rsquo;re using. It might mix in some PostgreSQL syntax when you are working with SQL Server, or it might use features that don&amp;rsquo;t exist in your version. It still often hallucinates syntax that doesn&amp;rsquo;t exist in any database I can find.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&amp;rsquo;ll often get incorrect results.&lt;/strong&gt; AI will generate queries that look reasonable but return wrong data, or that look unreasonable and also return the wrong data. (To be fair, the same thing can be said about &lt;em&gt;my&lt;/em&gt; queries.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Performance will be terrible.&lt;/strong&gt; Even if AI has the database schema you&amp;rsquo;re working with, unless you&amp;rsquo;ve set it up with a test environment with a realistic production dataset, it will not know how a query will be optimized. How could it? I&amp;rsquo;ve been working with SQL Server for 20 years and I can&amp;rsquo;t do this either. Query optimizers are complex, and the rules they apply to a query vary based on many factors, including data sizes, data distribution, and the resources assigned to the production instance.&lt;/p&gt;
&lt;h2 id="where-ai-is-fantastic-for-sql-code"&gt;Where AI is Fantastic for SQL Code&lt;/h2&gt;
&lt;p&gt;Even with its flaws, AI is a huge help at those &amp;ldquo;heavy review and testing&amp;rdquo; tasks when it comes to SQL code, whether you generated that code or wrote it yourself. This is simply a matter of having a helper to generate fairly basic procedural scripts following your instructions.&lt;/p&gt;
&lt;p&gt;I frequently use AI to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generate simple tests that prove the code does what it needs to do&lt;/li&gt;
&lt;li&gt;Generate complex tests that compare output of different versions of code to verify the output is correct&lt;/li&gt;
&lt;li&gt;Compare the performance of different versions of code to confirm a tuned version is actually faster with realistic data&lt;/li&gt;
&lt;li&gt;Ensure parameter sniffing-safe code by generating scripts or engineering a test harness to run code in different orders and cache plans at different points&lt;/li&gt;
&lt;li&gt;Research production data distribution by generating queries that help understand why queries perform differently in some environments rather than others&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these things can be done without AI tooling, of course. AI tooling makes it much more efficient to do this on a regular basis, and to think about ways to write tooling to build this functionality into the developer workflow itself.&lt;/p&gt;
&lt;h2 id="code-review-makes-you-better-and-builds-collaboration"&gt;Code Review Makes You Better and Builds Collaboration&lt;/h2&gt;
&lt;p&gt;I should mention that humans are reviewing all my code. While AI can be quite good at application languages, especially when it&amp;rsquo;s following common patterns, human review is still critical.&lt;/p&gt;
&lt;p&gt;Asking others for code reviews also helps remind me that I should be making time on a daily basis for doing code reviews. Code review is a skill that improves with practice. The more PRs I write, the better I get at reviewing other people&amp;rsquo;s code. I learn what to look for, what questions to ask, and how to provide helpful feedback.&lt;/p&gt;
&lt;p&gt;This bidirectional code review process has actually increased the amount of collaborative time I spend with software engineers. Instead of collaborating through handoffs and explanations, we collaborate through code review, which happens more frequently and on a more equal footing.&lt;/p&gt;
&lt;h2 id="app-code-projects-im-thinking-about"&gt;App Code Projects I&amp;rsquo;m Thinking About&lt;/h2&gt;
&lt;p&gt;The hackathon realization that I could own all my code changes opened up possibilities I hadn&amp;rsquo;t considered before. Now that I&amp;rsquo;m owning code changes completely, I have several code projects I&amp;rsquo;m thinking about that would help with database work and observability. These are projects that would have been much harder to pursue when I had to coordinate with developers for every application code change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Query tagging for observability.&lt;/strong&gt; I want to tag queries for better observability and improved analysis by code region. I want to automatically inject comments into code, including ORM code, to make it easier to tie queries back to the user experience and build analytics on that. I particularly want to use this to increase the visibility of &amp;ldquo;clusters&amp;rdquo; of ORM code that are related, but where queries have unique syntax. Owning both the SQL and application code means I can implement this tagging consistently across the stack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flexible load-testing datasets.&lt;/strong&gt; I&amp;rsquo;m interested in identifying characteristics of different dataset &amp;ldquo;flavors&amp;rdquo; that tend to generate different styles of query plans for customers, and building out flexible load-testing style datasets from them for improved load testing and code validation. One of the historical problems with keeping safe, sanitized or generated performance testing datasets up to date has always been the time and effort it requires. AI offers options for new workflows where it takes on a lot of the toil. Being able to write the scripts and tooling myself means I can iterate on this more quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple query plan paths.&lt;/strong&gt; I&amp;rsquo;m thinking about forcing multiple query plan &amp;ldquo;paths&amp;rdquo; for very frequent app queries by injecting a static comment value into some of the query strings. SQL Server&amp;rsquo;s ability to cache plans across sessions conserves memory and CPU, which is great, but for queries that execute at a very high frequency I don&amp;rsquo;t necessarily want a single query plan in production. If that plan regresses, it impacts everything calling it. I&amp;rsquo;m thinking about using comments injected into the SQL string at the app layer to help manage this in some scenarios so that I can still get a lot of query plan reuse without having all eggs in one basket. I like the idea of being able to specify having N different query plans per application server, but need to do more research to find the right design to test.&lt;/p&gt;
&lt;h2 id="what-this-means-for-your-career"&gt;What This Means for Your Career&lt;/h2&gt;
&lt;p&gt;Database roles are changing. The days of being purely a DBA who only touches SQL Server Management Studio are fading, even for stubborn creatures like me who are most comfortable when curled up snugly inside a complex query execution plan. I don&amp;rsquo;t have any regrets about the past or not having started out doing more application development &amp;ndash; there has been &lt;em&gt;plenty&lt;/em&gt; to keep me busy with databases. But, at this point, the barriers are low enough that it doesn&amp;rsquo;t make sense to NOT become more of a developer.&lt;/p&gt;
&lt;p&gt;The hackathon experience showed me that the barrier to owning all your code changes isn&amp;rsquo;t technical skill. It&amp;rsquo;s having a working dev environment where it&amp;rsquo;s safe for you to make mistakes and realizing that nothing is actually stopping you. AI agents make it practical to write application code even if you&amp;rsquo;re not an expert in C# or Python.&lt;/p&gt;
&lt;p&gt;Embracing development skills makes you more valuable. You can ship improvements faster. You can own problems completely. You can understand the full stack, from the database to the application to the user experience.&lt;/p&gt;
&lt;p&gt;This doesn&amp;rsquo;t mean you need to become a full-stack developer. It means you should be comfortable with these skills:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reading and critiquing code in multiple languages&lt;/td&gt;
&lt;td&gt;Enables you to own changes across the stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Using version control&lt;/td&gt;
&lt;td&gt;Essential for collaboration and code review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective prompting to write tests and the skills to review them for correctness&lt;/td&gt;
&lt;td&gt;Ensures your changes work correctly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shipping code through a release process&lt;/td&gt;
&lt;td&gt;Required for production deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The bad news is that we&amp;rsquo;re all developers now. The good news is that it doesn&amp;rsquo;t suck.&lt;/p&gt;</description></item><item><title>Adaptive Joins and Memory Grants in SQL Server</title><link>https://kendralittle.com/2026/01/26/adaptive-joins-and-memory-grants-in-sql-server/</link><pubDate>Mon, 26 Jan 2026 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2026/01/26/adaptive-joins-and-memory-grants-in-sql-server/</guid><description>&lt;p&gt;Adaptive joins let the optimizer choose between a Hash Join and a Nested Loop join at runtime, which can be fantastic for performance when row count estimates are variable. Recently, when &lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt; taught two days on TSQL at PASS Community Data Summit, a student asked why a query plan where an adaptive join used a Nested Loop at runtime ended up with a large memory grant anyway.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t remember the answer to this, but the great thing about co-teaching is that Erik did: adaptive joins always start executing as Hash Joins, which means they have to get memory grants upfront. Even if the query ultimately switches to a Nested Loop at runtime, that memory grant was already allocated. This has real implications for memory usage, especially in high-concurrency environments.&lt;/p&gt;
&lt;h2 id="what-are-adaptive-joins"&gt;What Are Adaptive Joins?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/intelligent-query-processing-details#batch-mode-adaptive-joins"&gt;Adaptive joins&lt;/a&gt; were introduced in SQL Server 2017. This join allows the query optimizer to choose between a batch mode Hash Join and a row mode Nested Loops Join at runtime, based on the actual number of rows processed in the Hash Join build phase.&lt;/p&gt;
&lt;p&gt;This is a departure from traditional query optimization, where the optimizer makes a one-time decision during plan compilation. With adaptive joins, the optimizer can &amp;ldquo;change its mind&amp;rdquo; during execution if the row counts it encounters indicate that a hash join isn&amp;rsquo;t needed and it can do something more lightweight for that execution of the query.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to stick to the basics in this post, but there are some excellent deep dives on how adaptive joins work listed at the end of this post.&lt;/p&gt;
&lt;h2 id="understanding-hash-join-build-and-probe-phases"&gt;Understanding Hash Join Build and Probe Phases&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/check-the-list.jpg" width="240"&gt;
&lt;/figure&gt;
&lt;p&gt;Let&amp;rsquo;s talk about how Hash Joins work. Hash Joins have two phases: &lt;strong&gt;build&lt;/strong&gt; and &lt;strong&gt;probe&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Imagine Erik and I are giving a training event. We hire a person to stand at the door and check people in. They know exactly who should be there, and they&amp;rsquo;re a lot tougher than they look.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build phase&lt;/strong&gt;: Before the event starts, we give the door person a list of all registered attendees. The information is in an Excel table (the world&amp;rsquo;s most popular database). In SQL Server terms, we have built a hash table in memory of all the people who are allowed in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Probe phase&lt;/strong&gt;: As people arrive, the door person checks each person&amp;rsquo;s name against the list&amp;ndash; they &lt;strong&gt;probe&lt;/strong&gt; the list to see if each person&amp;rsquo;s name has a matching value in the hash table. If your name is on the list, they let you through. If not, you&amp;rsquo;re turned away.&lt;/p&gt;
&lt;p&gt;In a hash join, SQL Server does the same thing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build phase&lt;/strong&gt;: Takes one incoming dataset (usually the smaller one) and builds a hash table in memory, organizing rows by their join key&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Probe phase&lt;/strong&gt;: Takes the other dataset it is joining and, for each row, looks up the join key in the hash table to find matching rows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;build&lt;/strong&gt; phase happens first and requires memory to store the hash table. The &lt;strong&gt;probe&lt;/strong&gt; phase happens second and uses that hash table to quickly find matches / check who is &amp;ldquo;on the list.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="all-adaptive-joins-are-born-as-hash-joins"&gt;All Adaptive Joins Are Born as Hash Joins&lt;/h2&gt;
&lt;p&gt;Key points to remember are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Hash joins require memory grants upfront&lt;/strong&gt; - The optimizer needs to allocate memory for the hash table before execution begins&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Row mode apply operations don&amp;rsquo;t need memory grants&lt;/strong&gt; - They can work with minimal memory, processing rows one at a time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The decision point happens after the build&lt;/strong&gt; - Once the build side of the hash join completes, SQL Server evaluates whether to continue with the batch mode hash join or switch to a row mode apply&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As Paul White emphasizes in his &lt;a href="https://www.sql.kiwi/2021/11/adaptive-join-threshold/"&gt;article on the adaptive join threshold&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One thing I want you to bear in mind throughout this piece is that an adaptive join always starts executing as a batch mode hash join. This is true even if the execution plan indicates the adaptive join will transition to apply.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even if the adaptive join ultimately switches to a row mode apply strategy (which is more efficient for small row counts), it still had to start as a hash join and request the memory grant upfront. The threshold calculation is based on cost estimates and the actual row count from the build phase.&lt;/p&gt;
&lt;h2 id="memory-grant-implications"&gt;Memory Grant Implications&lt;/h2&gt;
&lt;p&gt;This is where adaptive joins get interesting from a resource management perspective.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every execution of a query with an adaptive join must request a memory grant for the hash join&lt;/strong&gt;, even if the query ultimately switches to a row mode apply at runtime. This follows directly from Paul White&amp;rsquo;s point that adaptive joins always start executing as batch mode hash joins - the memory grant is requested before SQL Server knows whether it will need to switch strategies.&lt;/p&gt;
&lt;p&gt;This means:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Memory grants are requested on every execution&lt;/strong&gt; - Even if the adaptive join switches to row mode apply, the memory grant was already allocated for the hash join&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overall memory usage can increase&lt;/strong&gt; - If you have many queries using adaptive joins, your total memory grant usage will be higher than if those queries used row mode apply directly&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory pressure considerations&lt;/strong&gt; - In environments with limited memory or high concurrency, adaptive joins can contribute to memory pressure&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="when-to-optimize-with-temp-tables-and-dynamic-sql"&gt;When to Optimize with Temp Tables and Dynamic SQL&lt;/h2&gt;
&lt;p&gt;Because adaptive joins always request memory grants, sometimes it&amp;rsquo;s still worth optimizing queries using temp tables and dynamic SQL to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simplify optimization&lt;/strong&gt; - Break complex queries into simpler parts that the optimizer can handle better&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduce overall memory grants&lt;/strong&gt; - Smaller, simpler queries may not need adaptive joins and can use more efficient join strategies that don&amp;rsquo;t require memory grants&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improve plan stability&lt;/strong&gt; - Temp tables with statistics can lead to more predictable plans&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn&amp;rsquo;t mean you should avoid adaptive joins entirely - they&amp;rsquo;re a powerful feature that often improves performance. But understanding the memory grant implications helps you make informed decisions about query optimization strategies.&lt;/p&gt;
&lt;h2 id="example-query-with-adaptive-join"&gt;Example Query with Adaptive Join&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an example query using the StackOverflow2013 database that gets an Adaptive Join on my laptop instance running SQL Server 2025.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DropIndexes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Posts_CreationDate_Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Adaptive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Start&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This generates a plan with an adaptive join */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Adaptive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;20130101&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;20130514&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This reuses the plan and chooses to use the nested loop strategy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;on the adaptive join */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Adaptive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;20130101&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;20130102&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The actual query plan for the second execution looks like this:&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/adaptive-join.jpg" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;Memory grant information is not available in detail per operator, but you can see how much was granted for the query. In this case it is on the SELECT operator.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/adaptive-join-query-memory-grant.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Detail on how much of the memory grant was used and what was involved in &amp;ldquo;negotiating&amp;rdquo; the request is visible in the properties pane for the operator or in the XML of the plan.&lt;/p&gt;
&lt;h2 id="useful-adaptive-join-query-plan-operator-properties"&gt;Useful Adaptive Join Query Plan Operator Properties&lt;/h2&gt;
&lt;p&gt;When you look at properties of an adaptive join operator, you&amp;rsquo;ll see:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Actual Join Type&lt;/td&gt;
&lt;td&gt;Whether it picked nested loops or a hash join&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptive Threshold Rows&lt;/td&gt;
&lt;td&gt;The cardinality at which it switches between nested loops or a hash join&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash Keys Build&lt;/td&gt;
&lt;td&gt;The column(s) from the build input that are hashed into buckets to do the join&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash Keys Probe&lt;/td&gt;
&lt;td&gt;The columns(s) from the probe or nested loop (depending on what is selected) that are used to do the join&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/adaptive-join-properties.jpg" width="500"&gt;
&lt;/figure&gt;
&lt;h2 id="limitations-of-adaptive-joins"&gt;Limitations of Adaptive Joins&lt;/h2&gt;
&lt;p&gt;Adaptive joins have some &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/intelligent-query-processing#batch-mode-adaptive-joins"&gt;limitations&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Edition requirements&lt;/strong&gt;: Batch mode adaptive joins require Enterprise Edition (or Developer/Evaluation editions which include Enterprise features). They&amp;rsquo;re not available in Standard Edition, Web Edition, or Express Edition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility level requirements&lt;/strong&gt;: Database compatibility level 140 (SQL Server 2017) or higher is required.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch mode only&lt;/strong&gt;: Adaptive joins only work with batch mode execution, which requires either:
&lt;ul&gt;
&lt;li&gt;A columnstore index, or&amp;hellip;&lt;/li&gt;
&lt;li&gt;Batch Mode on Row Store (SQL Server 2019+, Enterprise Edition only, compatibility level 150 or higher).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited join transitions&lt;/strong&gt;: Adaptive joins only support transitions from batch mode hash joins to row mode apply (correlated nested loops) joins. They don&amp;rsquo;t support transitions to other join types like merge joins or row mode hash joins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Threshold calculation sensitivity&lt;/strong&gt;: The adaptive join threshold depends on the original cardinality estimate of the build input. As Paul White explains, this can lead to parameter sensitivity issues where the same cached plan behaves differently based on the initial cardinality estimate used during optimization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query structure requirements&lt;/strong&gt;: The query must qualify for batch mode execution, and the join must be eligible for the adaptive join optimization. Joins that would require a Key Lookup on the inner side are not eligible. Queries with certain constructs like &lt;code&gt;CROSS APPLY&lt;/code&gt; with &lt;code&gt;TOP&lt;/code&gt; or &lt;code&gt;OUTER APPLY&lt;/code&gt; may not qualify. As Erik Darling notes in his &lt;a href="https://dba.stackexchange.com/a/187577"&gt;detailed answer&lt;/a&gt;, there&amp;rsquo;s an Extended Event called &lt;code&gt;adaptive_join_skipped&lt;/code&gt; that can help you track when and why adaptive joins are skipped, if you like rocket science.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not supported in natively compiled modules&lt;/strong&gt;: Natively compiled T-SQL modules (In-Memory OLTP) don&amp;rsquo;t support adaptive joins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory overhead&lt;/strong&gt;: As we&amp;rsquo;ve discussed, adaptive joins always request memory grants for the hash join, even if they switch to row mode apply at runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="enabling-and-disabling-adaptive-joins"&gt;Enabling and Disabling Adaptive Joins&lt;/h2&gt;
&lt;p&gt;Adaptive joins are enabled by default when the requirements are met, but you can control them at the database or query level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Database scoped configuration&lt;/strong&gt; (affects all queries in the database):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQL Server 2017&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;To disable: &lt;code&gt;ALTER DATABASE SCOPED CONFIGURATION SET DISABLE_BATCH_MODE_ADAPTIVE_JOINS = ON;&lt;/code&gt; (yes, &lt;code&gt;ON&lt;/code&gt; means disable - it&amp;rsquo;s a double negative)&lt;/li&gt;
&lt;li&gt;To re-enable: &lt;code&gt;ALTER DATABASE SCOPED CONFIGURATION SET DISABLE_BATCH_MODE_ADAPTIVE_JOINS = OFF;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL Server 2019+&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;To disable: &lt;code&gt;ALTER DATABASE SCOPED CONFIGURATION SET BATCH_MODE_ADAPTIVE_JOINS = OFF;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To re-enable: &lt;code&gt;ALTER DATABASE SCOPED CONFIGURATION SET BATCH_MODE_ADAPTIVE_JOINS = ON;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Query hint&lt;/strong&gt; (affects only the specific query):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OPTION (USE HINT('DISABLE_BATCH_MODE_ADAPTIVE_JOINS'));&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The query hint takes precedence over the database scoped configuration setting.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn More&lt;/h2&gt;
&lt;p&gt;Adaptive joins are a powerful feature that can improve query performance by choosing the right join strategy at runtime.&lt;/p&gt;
&lt;p&gt;However, they ain&amp;rsquo;t free: they come with memory grant implications that are important to understand, especially in high-concurrency environments or systems with limited memory.&lt;/p&gt;
&lt;p&gt;The fact that adaptive joins always start as batch mode hash joins means they always request memory grants, even if they ultimately switch to row mode apply. These joins can be fantastic, but you probably don&amp;rsquo;t want them running all the time in a highly concurrent system.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read Paul White&amp;rsquo;s deep dive on &lt;a href="https://www.sql.kiwi/2021/11/adaptive-join-threshold/"&gt;the adaptive join threshold&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Watch Erik Darling&amp;rsquo;s video on &lt;a href="https://erikdarling.com/a-little-about-adaptive-joins-in-sql-server/"&gt;adaptive joins in SQL Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check out Hugo Kornelis&amp;rsquo; page explaining the &lt;a href="https://sqlserverfast.com/epr/adaptive-join/"&gt;adaptive join operator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Carrying Baggage Through Query Plans: Why Wide Queries Get Heavy</title><link>https://kendralittle.com/2026/01/19/carrying-baggage-through-query-plans-why-wide-queries-get-heavy/</link><pubDate>Mon, 19 Jan 2026 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2026/01/19/carrying-baggage-through-query-plans-why-wide-queries-get-heavy/</guid><description>&lt;p&gt;I see this pattern repeatedly: a &amp;ldquo;wide&amp;rdquo; query that returns many columns and less than 100k rows runs slowly. SQL Server gets slow when it drags large amounts of baggage through the entire query plan, like a solo traveler struggling with massive suitcases in an airport instead of picking them up close to their destination.&lt;/p&gt;
&lt;p&gt;SQL Server often minimizes data access by grabbing all the columns it needs early in query execution, &lt;strong&gt;then&lt;/strong&gt; doing joins and filters. This means presentation columns get picked up early.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Presentation columns&lt;/strong&gt;: This is a term I picked up from &lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt;. It refers to descriptive columns that you need in the final result set, but you aren't joining or filtering on them.
&lt;/div&gt;
&lt;p&gt;This pattern of picking up data baggage early and dragging it through the plan is also one of the reasons that SQL Server loves memory like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A raccoon loves garbage&lt;/li&gt;
&lt;li&gt;A penguin loves a good waddle&lt;/li&gt;
&lt;li&gt;A DBA loves to say &amp;ldquo;No&amp;rdquo;&lt;/li&gt;
&lt;li&gt;A MERGE statement loves chaos&lt;/li&gt;
&lt;li&gt;I love a stationary aisle&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;tldr&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Presentation columns you don&amp;rsquo;t need for filtering or sorting flow through expensive operations like sorts and hash joins. This frequently causes large memory grants, tempdb spills, and slow queries. Sometimes this is fine. Particularly for wide queries, it often isn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt; Separate the core data needed for filtering and sorting from the presentation columns. Two patterns work well when you need to handle a lot of &amp;ldquo;baggage&amp;rdquo; in a SQL Server query:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Temp tables:&lt;/strong&gt; Filter and sort with just the key columns, store your resulting core dataset in a temp table, then join back to get presentation columns. Best for complex logic and when you need statistics on an intermediate object.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Derived tables:&lt;/strong&gt; Use a nested derived table structure to keep the narrow dataset separate until the final join. If your query uses &lt;code&gt;TOP&lt;/code&gt;, push that into the derived table.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="info-note"&gt;
🤔 &lt;strong&gt;But why?&lt;/strong&gt; I suspect a major reason SQL Server makes these choices is that it has a horror of random IO, which still haunts it back from the days of rotating hard drives. I wish we had something like the &lt;a href="https://www.postgresql.org/docs/current/runtime-config-query.html"&gt;random page cost&lt;/a&gt; setting in Postgres to test with, as I'm curious how it would influence this. But we have other ways to tune.
&lt;/div&gt;
&lt;h2 id="why-this-is-often-inefficient"&gt;Why this is Often Inefficient&lt;/h2&gt;
&lt;p&gt;If the query needs to sort data (maybe for a merge join or an ORDER BY clause) or use hash joins for larger datasets, SQL Server must allocate memory to handle the data. And here&amp;rsquo;s the thing: it allocates memory for ALL the columns it has, not just the keys needed for sorting or joining.&lt;/p&gt;
&lt;p&gt;It can&amp;rsquo;t just leave the presentation columns behind&amp;ndash; it has to keep the data together as it flows through the plan.&lt;/p&gt;
&lt;p&gt;So the more columns you&amp;rsquo;re pulling back in your SELECT list, the heavier and slower these operations tend to get. SQL Server estimates memory grants based on the number of rows it expects to process and the width of all columns in those rows. Large memory grants &amp;ldquo;steal&amp;rdquo; memory from the buffer pool (it has to come from somewhere). Concurrent queries with large memory grants can lead to &lt;a href="https://www.sqlskills.com/help/waits/resource_semaphore/"&gt;RESOURCE SEMAPHORE&lt;/a&gt; waits, which can cause other queries to queue before they even get started.&lt;/p&gt;
&lt;h2 id="lets-work-through-an-example"&gt;Let&amp;rsquo;s Work Through an Example&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Spoiler, summary of results from below.&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Execution Time&lt;/th&gt;
&lt;th&gt;Memory Grant&lt;/th&gt;
&lt;th&gt;Max Used Memory&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Original query&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;13 seconds&lt;/td&gt;
&lt;td&gt;15 GB&lt;/td&gt;
&lt;td&gt;10.5 GB&lt;/td&gt;
&lt;td&gt;Letting the query optimizer make its own choices.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Temp table&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3 seconds&lt;/td&gt;
&lt;td&gt;6.8 GB (first query), 6.5 MB (second query)&lt;/td&gt;
&lt;td&gt;776 MB (first query), 0 (second query)&lt;/td&gt;
&lt;td&gt;Complex logic, need statistics, debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Derived table&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3 seconds&lt;/td&gt;
&lt;td&gt;7.8 GB&lt;/td&gt;
&lt;td&gt;784 MB&lt;/td&gt;
&lt;td&gt;You want to keep everything in one query and aren&amp;rsquo;t concerned about needing statistics between the steps.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here is the compat level and indexes I&amp;rsquo;m using. This was run against SQL Server 2025 on my laptop.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DropIndexes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Posts_OwnerUserId_Score_PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Comments_UserId_Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Comments_PostId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="a-wide-query-enters-the-chat"&gt;A Wide Query Enters the Chat&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve titled this query &amp;ldquo;StackOverflow Sick Burns and Top Pithyness.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The query finds high-scoring comments, where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comment has Score &amp;gt; 200 (required)&lt;/li&gt;
&lt;li&gt;Comment is NOT on a post the user created themselves&lt;/li&gt;
&lt;li&gt;If user has questions, the comment score must be higher than their highest scoring question&lt;/li&gt;
&lt;li&gt;Returns top 100 comments (by score) with user details, comment details, post details, and user&amp;rsquo;s highest scoring question (if any)&lt;/li&gt;
&lt;li&gt;Ensures one question per user (highest score, highest Id as tie-breaker) to prevent duplicate rows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The query takes &lt;strong&gt;13 seconds&lt;/strong&gt; on my laptop.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Core columns used for filtering/sorting */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scoreDifference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Comment details */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* large varchar - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: User details */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userDisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userUpvotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpVotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userDownvotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DownVotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userViews&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userAboutMe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AboutMe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Post that comment is on */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostOwnerDisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostOwnerReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: User&amp;#39;s highest question (if any) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Calculated columns */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;daysSinceComment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userReputationCategory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;New User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Regular User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Established User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Expert User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* excludes comments with NULL UserId (deleted users) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* excludes comments on community wiki posts (NULL OwnerUserId) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get one question per user: highest score, highest Id as tie-breaker */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Find questions with the maximum score for this user, highest Id as tie-breaker */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here is the overall shape of the actual query plan:&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/wide-query-original-plan.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The plan does some interesting things, but one choice that goes badly is that it picks up presentation columns &lt;code&gt;Body&lt;/code&gt;, &lt;code&gt;Tags&lt;/code&gt;, &lt;code&gt;Title&lt;/code&gt;, and more from Posts for the table aliased &lt;code&gt;q&lt;/code&gt;. It then feeds all that data into a Filter operator.&lt;/p&gt;
&lt;p&gt;This screenshot is from a different execution than the one in the plan shape above. In this execution the filter operator took even longer, but in both cases they output the same columns.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/wide-query-original-body-tags-title-early.jpg" width="600"&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;Body&lt;/code&gt; column is the whole text of questions &amp;ndash; that&amp;rsquo;s a lot of data. The query has a &lt;strong&gt;15 GB memory grant&lt;/strong&gt;, and it uses &lt;strong&gt;10.5 GB&lt;/strong&gt; of that.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/wide-query-original-15GB-memory-grant.jpg"
alt="Memory Grant data from the query plan showing 15 GB was granted and max used memory was over 10 GB"&gt;
&lt;/figure&gt;
&lt;h2 id="tuning-option-temp-table"&gt;Tuning Option: Temp Table&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s break the query into two steps.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, get the core data for filtering and joining into a temp table with just the key columns and reduce down to our 100 rows.&lt;/li&gt;
&lt;li&gt;Then join back to get the presentation columns.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am assuming I don&amp;rsquo;t need to order results in the second query and that ordering can be handled in the presentation layer, but ordering is required where we process &lt;code&gt;TOP&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This returns in &lt;strong&gt;3 seconds&lt;/strong&gt; on my laptop. The memory grant for the query that populates the temp table is &lt;strong&gt;6.8 GB&lt;/strong&gt; (it used 776 MB) and &lt;strong&gt;6.5 MB&lt;/strong&gt; for the query that reads from the temp table and joins to get detail data (it used 0).&lt;/p&gt;
&lt;p&gt;The main concept of this tuning approach is that we are specifying that we want to establish our &amp;ldquo;core&amp;rdquo; dataset and pop it into a temporary table before we fetch columns for presentation. SQL Server loves a temporary table because it can automatically create column statistics on it, which also can help it optimize the second query well.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* excludes comments with NULL UserId (deleted users) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* excludes comments on community wiki posts (NULL OwnerUserId) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get one question per user: highest score, highest Id as tie-breaker */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Find questions with the maximum score for this user, highest Id as tie-breaker */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Core columns used for filtering/sorting */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scoreDifference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Comment details */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* large varchar - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: User details */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userDisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userUpvotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpVotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userDownvotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DownVotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userViews&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userAboutMe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AboutMe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Post that comment is on */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostOwnerDisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostOwnerReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: User&amp;#39;s highest question (if any) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Calculated columns */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;daysSinceComment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userReputationCategory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;New User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Regular User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Established User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Expert User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommentId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;When to use temp tables:&lt;/strong&gt; Use this approach when you need column statistics for optimization, have complex multi-step logic that benefits from breaking into stages, or want to debug intermediate results. Temp tables also work well when you need to reuse the core dataset multiple times.&lt;/p&gt;
&lt;h2 id="tuning-option-derived-table"&gt;Tuning Option: Derived Table&lt;/h2&gt;
&lt;p&gt;Do we really &lt;strong&gt;need&lt;/strong&gt; the temp table though?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how far we can get while staying in a single query. This tuning option focuses on defining the core dataset in derived tables or &lt;code&gt;CROSS APPLY&lt;/code&gt;s, then joining back to get the wider presentation columns. In this example we&amp;rsquo;re using &lt;code&gt;TOP&lt;/code&gt;, so we push that into a derived table and join to it. The same pattern can work for queries without &lt;code&gt;TOP&lt;/code&gt;: use the derived table to separate the narrow filtering/sorting dataset from the presentation columns.&lt;/p&gt;
&lt;p&gt;This query finishes on my laptop in &lt;strong&gt;3 seconds&lt;/strong&gt;. The memory grant is &lt;strong&gt;7.8 GB&lt;/strong&gt;, and it used &lt;strong&gt;784 MB&lt;/strong&gt; of that. If this was an actual production query I&amp;rsquo;d figure out how to tone that grant down a bit and tune this more. But for the purpose of a relatively quick post, this makes the general point.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use derived tables:&lt;/strong&gt; Use this approach when you want a single query but can accept higher memory grants (or take the time to tune them away), or when the query runs infrequently enough that the memory grant isn&amp;rsquo;t a concern.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Core columns used for filtering/sorting */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scoreDifference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Comment details */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* large varchar - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: User details */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userDisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userUpvotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpVotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userDownvotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DownVotes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userViews&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userAboutMe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AboutMe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Post that comment is on */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostOwnerDisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentPostOwnerReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: User&amp;#39;s highest question (if any) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LOB column - presentation only */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Presentation-only: Calculated columns */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;daysSinceComment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userReputationCategory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;New User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Regular User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Established User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Expert User&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* excludes comments with NULL UserId (deleted users) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* excludes comments on community wiki posts (NULL OwnerUserId) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get one question per user: highest score, highest Id as tie-breaker */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Find questions with the maximum score for this user, highest Id as tie-breaker */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qMaxScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userHighestQuestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionScore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommentId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questionId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here is the overall shape of the query plan:&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/wide-query-derived-table.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The use of the derived table forces SQL Server to push that portion of the query into the block to the right, then joins to the other tables are processed.&lt;/p&gt;
&lt;p&gt;Do note that I wrote &lt;strong&gt;forces&lt;/strong&gt;: similar to the temp table rewrite, we are making a choice that dictates how this will be processed. We are removing choices from the query optimizer.&lt;/p&gt;
&lt;h2 id="common-pitfalls-to-watch-for"&gt;Common Pitfalls to Watch For&lt;/h2&gt;
&lt;p&gt;When splitting queries to reduce baggage, watch out for these issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Forgetting join keys:&lt;/strong&gt; Make sure your narrow dataset includes all the keys you need to join back to get the presentation columns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NULL handling:&lt;/strong&gt; When splitting queries, consider how NULLs are handled. The original query might have handled NULLs differently than your split version.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Over-optimizing:&lt;/strong&gt; If a query runs infrequently, the optimization effort might not be worth it. Focus on queries that run often or are causing performance problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lightening-the-load"&gt;Lightening the Load&lt;/h2&gt;
&lt;p&gt;When SQL Server carries wide columns through expensive operations like sorts and hash joins, it requires significant memory and slows down your queries. By separating the core data you need for filtering and sorting from the presentation columns, you can significantly reduce the memory footprint and improve query performance.&lt;/p&gt;
&lt;p&gt;The next time you see a slow query with a wide result set, check the execution plan. Look at operators like Sort or Hash Match and examine their &amp;ldquo;Output List&amp;rdquo; or &amp;ldquo;Defined Values&amp;rdquo; properties. If you see many more columns than are needed for the operation itself, you&amp;rsquo;ve found the baggage. Try one of these two approaches to lighten the load.&lt;/p&gt;
&lt;p&gt;If the query runs very frequently, it&amp;rsquo;s worth considering your options for whether application caching might help out, too. As they say, the fastest query is the one you never run.&lt;/p&gt;</description></item><item><title>Testing SQL Server 2025 Resource Governor tempdb Limits with a Query that Spills a Terabyte</title><link>https://kendralittle.com/2026/01/12/testing-sql-server-2025-resource-governor-tempdb-limits/</link><pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2026/01/12/testing-sql-server-2025-resource-governor-tempdb-limits/</guid><description>&lt;p&gt;SQL Server 2025 introduces a new &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor"&gt;Resource Governor&lt;/a&gt; capability to manage tempdb usage, along with making &lt;a href="https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2025#standard-edition"&gt;Resource Governor available in Standard Edition&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wondered: can Resource Governor&amp;rsquo;s new tempdb feature help contain queries that don&amp;rsquo;t use temporary tables, but which spill massive amounts of data to tempdb? The &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/tempdb-space-resource-governance#how-it-works"&gt;docs say yes&lt;/a&gt;, but I always like to get hands-on experience when I can.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got an awful query that spills like a soft-serve machine choosing violence. Let&amp;rsquo;s test drive the new tempdb governance features in SQL Server 2025.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Sort_Spill_Big.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="meet-our-test-query-whose-sort-spills-a-terabyte-of-data"&gt;Meet our Test Query Whose Sort Spills a Terabyte of Data&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using the StackOverflow2013 database with a query built to spill. The query gets a 15 GB memory grant due to the combination of window functions calculating aggregates across large partitions and multiple LEFT JOINs producing duplicate rows for windowing calculations.&lt;/p&gt;
&lt;p&gt;That 15 GB memory grant is far too little for the amount of data going into a sort operator in the query plan, and the memory spill to disk easily fills up my 1 TB of local free space on my laptop if it&amp;rsquo;s not contained.&lt;/p&gt;
&lt;p&gt;First, this script configures database settings and indexes used by the query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DropIndexes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Posts_PostTypeId_ETC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerId&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Comments_PostId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And this script is the spilling query itself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This query is not good for much except tempdb spills. */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionViews&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionAnswerCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionCommentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionTags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionLastActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerLocation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerCreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerOwnerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerOwnerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerOwnerReputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TotalUpVotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VoteTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TotalFavorites&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VoteTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RecentCommentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2012-01-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerBadgeCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QuestionOwnerGoldBadges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Legendary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Enlightened&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Great Answer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Votes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Badges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BETWEEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;49999&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VoteTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2012-01-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="sql-server-2025-resource-governor-tempdb-space-governance"&gt;SQL Server 2025 Resource Governor tempdb Space Governance&lt;/h2&gt;
&lt;p&gt;SQL Server 2025 introduces &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/tempdb-space-resource-governance"&gt;Resource Governor tempdb Space Governance&lt;/a&gt;, which allows you to set limits in one of two ways.&lt;/p&gt;
&lt;p&gt;To constrain tempdb usage there are two &amp;ldquo;group&amp;rdquo; level options as described in &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql"&gt;Create Workload Group&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GROUP_MAX_TEMPDB_DATA_MB&lt;/strong&gt;: &amp;ldquo;the maximum amount of space that a workload group can consume in the tempdb data files, in megabytes&amp;hellip; The limit is for the total space consumed in tempdb by all sessions in a workload group.&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GROUP_MAX_TEMPDB_DATA_PERCENT&lt;/strong&gt;: &amp;ldquo;Specifies the maximum amount of space that a workload group can consume in the tempdb data files, in percent of the maximum tempdb size.&amp;rdquo; There&amp;rsquo;s a &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/tempdb-space-resource-governance#percent-limit-configuration"&gt;table in the docs&lt;/a&gt; that gets into the configuration requirements for this setting to be in effect. One requirement is that this doesn&amp;rsquo;t work if you also have GROUP_MAX_TEMPDB_DATA_MB configured for the workload group.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a query exceeds the configured limit, SQL Server aborts it with &lt;code&gt;error 1138, severity 17, Could not allocate a new page for database 'tempdb' because that would exceed the limit set for workload group 'workload-group-name'&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="configure-resource-governor-for-our-test"&gt;Configure Resource Governor for our Test&lt;/h2&gt;
&lt;p&gt;To test tempdb governance with our spilling query, we will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor-resource-pool"&gt;resource pool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor-workload-group"&gt;workload group&lt;/a&gt; with tempdb limits that uses the resource pool&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor-classifier-function"&gt;classifier function&lt;/a&gt; to route our test queries to that workload group&lt;/li&gt;
&lt;li&gt;Enable Resource Governor&lt;/li&gt;
&lt;li&gt;Verify the configuration&lt;/li&gt;
&lt;li&gt;Run the test query from a classified session&lt;/li&gt;
&lt;li&gt;Observe the tempdb usage of the pool by querying &lt;code&gt;sys.dm_resource_governor_workload_groups&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="step-1-create-a-resource-pool"&gt;Step 1: Create a Resource Pool&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;POOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tempdb_spill_test_pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A resource pool defines the physical resources available to the group of queries that you classify to use the pool. The resource pool lets you set things like CPU percentage limits with &lt;code&gt;MAX_CPU_PERCENT&lt;/code&gt; and memory limits with &lt;code&gt;MAX_MEMORY_PERCENT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The tempdb governance feature does not have any options on the resource pool itself, the options are all on the workload group. You can use the default pool if you want, but I think it&amp;rsquo;s useful to create separate pools for different workloads for tracking, and you may wish to apply pool limits at some time in the future.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m creating a basic pool without specifying resource limits.&lt;/p&gt;
&lt;h2 id="step-2-create-a-workload-group-with-tempdb-limits"&gt;Step 2: Create a Workload Group with tempdb Limits&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WORKLOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tempdb_spill_test_group&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GROUP_MAX_TEMPDB_DATA_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10240&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;USING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tempdb_spill_test_pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;USING&lt;/code&gt; clause assigns this workload group to our resource pool. Sessions classified into this workload group get the tempdb &lt;code&gt;GROUP_MAX_TEMPDB_DATA_MB&lt;/code&gt; limit (10 GB) and any other resource limits we put on the pool.&lt;/p&gt;
&lt;p&gt;Some workload group options allow you to define policies for the whole group, such as &lt;code&gt;GROUP_MAX_REQUESTS&lt;/code&gt;. Some options define policies for individual requests within the group. For example, &lt;code&gt;REQUEST_MAX_MEMORY_GRANT_PERCENT&lt;/code&gt; and &lt;code&gt;REQUEST_MAX_CPU_TIME_SEC&lt;/code&gt; each allow you to limit the resources for individual queries that run in the pool. You can also set the &lt;code&gt;MAX_DOP&lt;/code&gt; (maximum degree of parallelism) for all requests in the pool.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Don't Read Too Much Into This&lt;/strong&gt;: I'm not saying 10 GB is a "best practice" value for how much space to allow a workload group to use in tempdb. Actual tempdb requirements vary dramatically across production environments. Some workloads need very little, some need a lot. Baseline a specific system to know what's appropriate.
&lt;/div&gt;
&lt;h2 id="step-3-create-a-classifier-function"&gt;Step 3: Create a Classifier Function&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tempdb_test_classifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysname&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEMABINDING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;workload_group_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APP_NAME&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb_spill_test&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;workload_group_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb_spill_test_group&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;workload_group_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A classifier function is a scalar user-defined function that runs for every new connection. It returns the name of the workload group to assign the session to. The function must be created in the &lt;code&gt;master&lt;/code&gt; database with &lt;code&gt;SCHEMABINDING&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Only one classifier function can be active on a given SQL Server Instance at a time.&lt;/p&gt;
&lt;p&gt;Classifier functions commonly use session properties like &lt;code&gt;APP_NAME()&lt;/code&gt;, &lt;code&gt;SUSER_SNAME()&lt;/code&gt; (login name), &lt;code&gt;HOST_NAME()&lt;/code&gt; (client computer name), or custom logic to route sessions. The function executes during login, so keep it lightweight and fast to avoid impacting performance at login time and to avoid connection timeouts.&lt;/p&gt;
&lt;p&gt;This also means that when you enable Resource Governor, sessions that are already connected will not use the pools or workload groups you&amp;rsquo;ve newly configured. Sessions are only classified the next time they log in.&lt;/p&gt;
&lt;p&gt;The classifier function I&amp;rsquo;m using here checks the application name, because that&amp;rsquo;s very simple to use for testing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a session connects with the application name &amp;rsquo;tempdb_spill_test&amp;rsquo;, it assigns that session to tempdb_spill_test_group.&lt;/li&gt;
&lt;li&gt;All other sessions go to the &amp;lsquo;default&amp;rsquo; workload group.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-4-configure-and-enable-resource-governor"&gt;Step 4: Configure and Enable Resource Governor&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GOVERNOR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLASSIFIER_FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tempdb_test_classifier&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GOVERNOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-5-verify-the-configuration"&gt;Step 5: Verify the Configuration&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;group_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_max_tempdb_data_mb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_max_tempdb_data_percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource_governor_workload_groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_resource_governor_resource_pools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb_spill_test_group&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The query results show that our workload group is configured with the 10 GB limit for tempdb data, and that the group is assigned to the resource pool we created as well.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/resource_governor_tempdb_configuration.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="step-6-run-the-test-query-in-a-classified-session"&gt;Step 6: Run the Test Query in a Classified Session&lt;/h2&gt;
&lt;p&gt;To run the test query under resource governance, open a new query window in SSMS and set the application name in the connection properties. If you&amp;rsquo;re using &lt;a href="https://learn.microsoft.com/en-us/ssms/install/install"&gt;SQL Server Management Studio 22&lt;/a&gt;, here are the steps in the new database connection window:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;File&lt;/strong&gt;, &lt;strong&gt;New&lt;/strong&gt;, &lt;strong&gt;Database Engine Query&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In the connection dialog, select &lt;strong&gt;Advanced&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Context&lt;/strong&gt; set the application name to: &lt;code&gt;tempdb_spill_test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;OK&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Make sure ServerName and other connection info is set correctly and select &lt;strong&gt;Connect&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run this query in your new session to verify that it has been classified correctly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workload_group_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_resource_governor_workload_groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;SPID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should return &lt;code&gt;tempdb_spill_test_group&lt;/code&gt; as the workload group name.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/query_your_current_workload_group.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Now run the &lt;a href="#meet-our-test-query-whose-sort-spills-a-terabyte-of-data"&gt;test query above&lt;/a&gt; in this session.&lt;/p&gt;
&lt;p&gt;The spilling query hits the 10 GB limit on my laptop in around 17 seconds.&lt;/p&gt;
&lt;p&gt;When it hits the limit, SQL Server aborts the query and I see the foretold error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Msg 1138, Level 17, State 1, Line &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Could not allocate a new page &lt;span class="k"&gt;for&lt;/span&gt; database &lt;span class="s1"&gt;&amp;#39;tempdb&amp;#39;&lt;/span&gt; because that would exceed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;the limit &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; workload group &lt;span class="s1"&gt;&amp;#39;tempdb_spill_test_group&amp;#39;&lt;/span&gt;, group_id 256.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-7-query-tempdb-usage-and-violations-from-sysdm_resource_governor_workload_groups"&gt;Step 7. Query tempdb Usage and Violations from &lt;code&gt;sys.dm_resource_governor_workload_groups&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Since the query fails quickly, it&amp;rsquo;s easy to run it multiple times and watch the workload group&amp;rsquo;s tempdb usage while it is running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tempdb_data_space_kb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;peak_tempdb_data_space_kb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_tempdb_data_limit_violation_count&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_resource_governor_workload_groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb_spill_test_group&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s an example of what the output looks like on my laptop:&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/tempdb_usage_resource_group.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="the-total_tempdb_data_limit_violation_count-column-does-not-count-the-number-of-queries-that-failed"&gt;The total_tempdb_data_limit_violation_count column does not count the number of queries that failed&lt;/h2&gt;
&lt;p&gt;This column in &lt;code&gt;sys.dm_resource_governor_workload_groups&lt;/code&gt; &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-resource-governor-workload-groups-transact-sql"&gt;is defined as&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The number of times a request was aborted with error 1138 because it would exceed the limit on tempdb data space consumption for the workload group.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In some brief testing, I usually see this number increases by 8 on my laptop every time my query hits the limit and is aborted. The query is running at max degree of parallelism 8 on my laptop. Sometimes I see it increment by a different amount, though, such as 5.&lt;/p&gt;
&lt;p&gt;Was the effective maxdop lowered for tha run for some reason? I&amp;rsquo;m not sure, I haven&amp;rsquo;t looked into it that much, but the increment is definitely not the count of individual query runs that failed.&lt;/p&gt;
&lt;h2 id="cleanup-remove-resource-governor-configuration"&gt;Cleanup: Remove Resource Governor Configuration&lt;/h2&gt;
&lt;p&gt;This script undoes what the demo above sets up. You need to close all active sessions that are using the workload group/ resource pool before this will complete successfully.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GOVERNOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISABLE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GOVERNOR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLASSIFIER_FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GOVERNOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tempdb_test_classifier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WORKLOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tempdb_spill_test_group&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RESOURCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;POOL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tempdb_spill_test_pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="did-resource-governance-help-with-tempdb-spills"&gt;Did Resource Governance Help with tempdb Spills?&lt;/h2&gt;
&lt;p&gt;✅ Yes, this Resource Governor feature protected my hard drive from the mad space consumption of this truly terrible query. This confirms what the documentation says: the tempdb space governance feature does not just apply to temp table usage, it also helps contain memory spills in query plan operators.&lt;/p&gt;
&lt;p&gt;My takeaways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This is a great feature to have in SQL Server&lt;/strong&gt;, particularly if you have large amounts of data and queries can&amp;rsquo;t always be tested with production dataset sizes before getting released into your SQL Server. If you have auto-generated code or folks who need to rapidly develop queries for analytics, you&amp;rsquo;re probably pretty excited to get your hands on this feature.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This tempdb governance feature doesn&amp;rsquo;t provide warnings or controlled degradation&lt;/strong&gt;. It&amp;rsquo;s a hard limit: stay under it or queries will fail. This makes it useful for protecting the server, but it means you need to tune your queries or increase memory grants to avoid hitting the limit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;total_tempdb_data_limit_violation_count&lt;/code&gt; column in &lt;code&gt;sys.dm_resource_governor_workload_groups&lt;/code&gt; is confusing&lt;/strong&gt;. The docs read like it counts individual queries that fail, when in fact it seems to count something more like threads that fail when they hit the limit. This doesn&amp;rsquo;t seem like a huge problem as long as you don&amp;rsquo;t misinterpret it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overall, I think this feature is a welcome addition to Resource Governor, and it&amp;rsquo;s terrific that Resource Governor is available for Standard Edition in SQL Server 2025.&lt;/p&gt;</description></item><item><title>How to Trace Trigger Executions with Query Store and Extended Events</title><link>https://kendralittle.com/2026/01/05/how-to-trace-trigger-executions-with-query-store-and-extended-events/</link><pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2026/01/05/how-to-trace-trigger-executions-with-query-store-and-extended-events/</guid><description>&lt;p&gt;Triggers can be tricky to observe in SQL Server. When you need to understand exactly what a trigger is doing and what it impacts, Query Store and Extended Events both have something to offer, but using them effectively requires navigating some confusing nuances. Query Store tracks query-level executions aggregated by query_id, but has a habit of generating a lot of query_ids with different context settings for triggers. Extended Events can capture trigger module starts and individual statement completions within triggers.&lt;/p&gt;
&lt;p&gt;This post walks through setting up both observation methods on a test trigger, then compares what each one shows. You&amp;rsquo;ll see how Query Store data gets spread across multiple query_ids and context_settings_id values, a variety of ways to trace triggers in XEvents, and why the numbers don&amp;rsquo;t always match up exactly between traces and Query Store.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using the StackOverflow2013 sample database on SQL Server 2025 Developer Edition to create a trigger, test it with various DML operations (INSERT, UPDATE, DELETE, MERGE, and dynamic SQL), then analyze the results from both observation methods.&lt;/p&gt;
&lt;h2 id="setup-enable-and-clear-query-store"&gt;Setup: Enable and Clear Query Store&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s make sure Query Store is enabled. This clears all data from Query Store so be careful where you run this.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OPERATION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;READ_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_CAPTURE_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_STORAGE_SIZE_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEANUP_POLICY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;STALE_QUERY_THRESHOLD_DAYS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* WARNING: Clear Query Store data for clean testing */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This removes all Query Store data - use with caution in production */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEAR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="setup-create-the-audit-table"&gt;Setup: Create the Audit Table&lt;/h2&gt;
&lt;p&gt;Next, create a simple audit table to track changes to the Posts table:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.AuditPosts&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AuditPostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_AuditPosts_AuditPostsId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuditPostsId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="setup-create-the-trigger-on-posts"&gt;Setup: Create the Trigger on Posts&lt;/h2&gt;
&lt;p&gt;Now I&amp;rsquo;m creating a wild and safety-free trigger on the Posts table. This trigger has no safety checks (no IF EXISTS blocks) and uses UNION ALL with separate queries for each column to handle NULLs.&lt;/p&gt;
&lt;p&gt;When we modify the Posts table (INSERT, UPDATE, or DELETE), the trigger automatically fires and performs these actions:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;When we modify Posts&lt;/th&gt;
&lt;th&gt;Trigger behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;INSERT or UPDATE&lt;/td&gt;
&lt;td&gt;Trigger updates &lt;code&gt;LastActivityDate&lt;/code&gt; on the Posts table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INSERT&lt;/td&gt;
&lt;td&gt;Trigger adds 4 rows to AuditPosts (one for each of Title, PostTypeId, OwnerUserId, Score) with Action = &amp;lsquo;I&amp;rsquo;, using separate UNION ALL queries that handle NULL values for Title and OwnerUserId&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UPDATE&lt;/td&gt;
&lt;td&gt;Trigger adds 4 rows to AuditPosts with Action = &amp;lsquo;U&amp;rsquo; if any of Title, PostTypeId, OwnerUserId, or Score changed (inserts all 4 rows with &amp;ldquo;before&amp;rdquo; values from the deleted table when any column changes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;Trigger adds 4 rows to AuditPosts with Action = &amp;lsquo;D&amp;rsquo;, using separate UNION ALL queries that handle NULL Title for answers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; All modifications to AuditPosts come from the trigger. We never directly INSERT, UPDATE, or DELETE from AuditPosts. We only modify Posts, and the trigger handles all AuditPosts changes automatically.&lt;/p&gt;
&lt;p&gt;By &amp;ldquo;safety-free&amp;rdquo;, I mean this trigger lacks the Good Things in Trigger Life:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s not &lt;a href="https://erikdarling.com/how-to-get-sql-server-triggers-to-selectively-fire/"&gt;selectively firing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It does not check if &lt;code&gt;ROWCOUNT_BIG() = 0&lt;/code&gt; and return if nothing happens.&lt;/li&gt;
&lt;li&gt;It doesn&amp;rsquo;t do any of the following:
&lt;ul&gt;
&lt;li&gt;Existence checks (no &lt;code&gt;EXISTS&lt;/code&gt; or &lt;code&gt;NOT EXISTS&lt;/code&gt; clauses) to see if the inserted and deleted tables have rows in them&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/update-trigger-functions-transact-sql"&gt;UPDATE() trigger function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/columns-updated-transact-sql"&gt;COLUMNS_UPDATED() trigger function&lt;/a&gt; to test if the trigger should execute certain actions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead, it uses only NULL comparisons to distinguish between INSERT, UPDATE, and DELETE operations. For INSERT operations, it joins
&lt;code&gt;inserted&lt;/code&gt; to &lt;code&gt;deleted&lt;/code&gt; using LEFT JOIN and check if &lt;code&gt;deleted.Id&lt;/code&gt; IS NULL. For DELETE operations, we check if &lt;code&gt;inserted.Id&lt;/code&gt; IS NULL when joining &lt;code&gt;deleted&lt;/code&gt; to &lt;code&gt;inserted&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRIGGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tr_Posts_Audit_No_Safeties&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRIGGER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tr_Posts_Audit_No_Safeties&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AFTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Update LastActivityDate on INSERT and UPDATE */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Handle INSERT - only when deleted table is empty */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PostTypeId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OwnerUserId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OwnerUserId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Score&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Handle UPDATE - only if Title, PostTypeId, OwnerUserId, or Score changed */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PostTypeId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OwnerUserId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OwnerUserId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Score&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Handle DELETE - use LEFT JOIN to inserted and check if inserted.Id IS NULL */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PostTypeId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OwnerUserId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OwnerUserId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Score&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="setup-create-query-store-history-capture-helper"&gt;Setup: Create Query Store History Capture Helper&lt;/h2&gt;
&lt;p&gt;To track which Query Store query IDs correspond to which operations, we&amp;rsquo;ll create a helper procedure that captures Query Store data after each step in the test procedure. This eliminates guesswork when analyzing Query Store output.&lt;/p&gt;
&lt;p&gt;The helper procedure queries Query Store for all trigger-related queries and saves them to a history table with a step description. This lets us see exactly which query IDs were created or updated after each operation.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Create table to store Query Store history with step descriptions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.QueryStoreHistory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;history_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;runtime_stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_cpu_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_duration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdev_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetimeoffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;captured_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYSDATETIME&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Helper procedure to capture Query Store data for trigger queries */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Step number for ordering (1, 2, 3, etc.) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Description of what step just executed */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Strip HTML tags from step description before storing */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;clean_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Remove common HTML tags */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;clean_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;clean_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;clean_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;clean_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;/strong&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;runtime_stats_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdev_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;clean_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;runtime_stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_cpu_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_duration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdev_rowcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdev_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1900-01-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetimeoffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get latest runtime stats entry for each plan */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STUFF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_PADDING ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_PADDING OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_NULLS ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_NULLS OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, QUOTED_IDENTIFIER ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, QUOTED_IDENTIFIER OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ARITHABORT ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ARITHABORT OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ARITHIGNORE ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ARITHIGNORE OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, NUMERIC_ROUNDABORT ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, NUMERIC_ROUNDABORT OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_WARNINGS ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_WARNINGS OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_NULL_DFLT_ON ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, ANSI_NULL_DFLT_ON OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, CONCAT_NULL_YIELDS_NULL ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, CONCAT_NULL_YIELDS_NULL OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, CURSOR_CLOSE_ON_COMMIT ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, CURSOR_CLOSE_ON_COMMIT OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, IMPLICIT_TRANSACTIONS ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, IMPLICIT_TRANSACTIONS OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, TEXTSIZE 2147483647&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, TEXTSIZE default&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, DATE FIRST 1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, DATE FIRST 7&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, DATE FORMAT mdy&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, DATE FORMAT dmy&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16384&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16384&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, LANGUAGE us_english&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, LANGUAGE other&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UNKNOWN&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdev_rowcount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qst&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_context_settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qcs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;set_options_decoded&lt;/code&gt; column decodes the &lt;code&gt;set_options&lt;/code&gt; bitmask into human-readable SET option values. The bitmask decoding logic uses standard SQL Server SET option bitmask values documented in Microsoft's documentation for &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-plan-attributes-transact-sql"&gt;sys.dm_exec_plan_attributes&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-context-settings-transact-sql"&gt;sys.query_context_settings&lt;/a&gt;. For more information on how SET options affect query performance and execution plans, see &lt;a href="https://www.sommarskog.se/query-plan-mysteries.html"&gt;Erland Sommarskog's article "Slow in the Application, Fast in SSMS?"&lt;/a&gt;.
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;sp_CaptureQueryStoreHistory&lt;/code&gt; procedure queries Query Store for all queries related to the trigger and saves detailed information to &lt;code&gt;dbo.QueryStoreHistory&lt;/code&gt; with a step description. It captures all rows from Query Store without grouping, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query ID, query text ID, plan ID, and runtime stats ID&lt;/li&gt;
&lt;li&gt;Context settings ID and decoded SET options (including &lt;code&gt;IMPLICIT_TRANSACTIONS&lt;/code&gt; status)&lt;/li&gt;
&lt;li&gt;Query SQL text&lt;/li&gt;
&lt;li&gt;Runtime statistics (execution count, CPU time, duration, logical I/O reads, last execution time)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The test procedure calls this helper after each step, building a detailed history that maps Query Store data to specific operations. Analyze and aggregate this data later as needed.&lt;/p&gt;
&lt;h2 id="setup-create-test-data-procedure"&gt;Setup: Create Test Data Procedure&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s create a stored procedure that fires the trigger in various ways. The procedure also includes a MERGE statement and dynamic SQL with sp_executesql (inspired by &lt;a href="https://dba.stackexchange.com/a/328057/471"&gt;Paul White&amp;rsquo;s answer on StackOverflow&lt;/a&gt;) to demonstrate additional trigger firing scenarios:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_TestTriggerFires&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Set consistent options for Query Store tracking */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ANSI_NULLS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTED_IDENTIFIER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ARITHABORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NUMERIC_ROUNDABORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IMPLICIT_TRANSACTIONS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Store the IDs for later updates and deletes */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;inserted_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;strong&amp;gt;Step A:&amp;lt;/strong&amp;gt; Insert 10 rows: 5 questions (PostTypeId=1), 5 answers (PostTypeId=2) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Use OUTPUT clause to capture IDs immediately - no table scan needed */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FavoriteCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OUTPUT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;inserted_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test question body for trigger testing&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;test&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test Question 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test question body 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;test&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test Question 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test question body 3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;test&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test Question 3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test question body 4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;test&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test Question 4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test question body 5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;test&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test Question 5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test answer body 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test answer body 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test answer body 3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test answer body 4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test answer body 5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Split inserted IDs into question and answer tables based on PostTypeId */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;inserted_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ii&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;inserted_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ii&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step A */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step A:&amp;lt;/strong&amp;gt; INSERT 10 rows&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Update all 10 rows with various changes */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Question 1: Update Title */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Updated Test Question 1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step B */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step B:&amp;lt;/strong&amp;gt; UPDATE Question 1 (Title)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Question 2: Update CommentCount (should NOT trigger audit) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step C */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step C:&amp;lt;/strong&amp;gt; UPDATE Question 2 (CommentCount)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Question 3: Update Body (should NOT trigger audit) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Updated body text&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step D */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step D:&amp;lt;/strong&amp;gt; UPDATE Question 3 (Body)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Question 4: Update LastEditDate (should NOT trigger audit) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastEditDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step E */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step E:&amp;lt;/strong&amp;gt; UPDATE Question 4 (LastEditDate)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Question 5: Update Score */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step F */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step F:&amp;lt;/strong&amp;gt; UPDATE Question 5 (Score)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Answer 1: Update OwnerUserId */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step G */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step G:&amp;lt;/strong&amp;gt; UPDATE Answer 1 (OwnerUserId)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Answer 2: Update CommentCount (should NOT trigger audit) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step H */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step H:&amp;lt;/strong&amp;gt; UPDATE Answer 2 (CommentCount)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Answer 3: Update Body (should NOT trigger audit) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Updated answer body&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step I */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step I:&amp;lt;/strong&amp;gt; UPDATE Answer 3 (Body)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Answer 4: Update LastEditDate (should NOT trigger audit) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastEditDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step J */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step J:&amp;lt;/strong&amp;gt; UPDATE Answer 4 (LastEditDate)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Answer 5: Update Score */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step K */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step K:&amp;lt;/strong&amp;gt; UPDATE Answer 5 (Score)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Delete all 10 rows */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;question_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;answer_ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step L */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step L:&amp;lt;/strong&amp;gt; DELETE 10 rows&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* MERGE statement */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* If a matching row exists, update it; otherwise insert a new row */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* This fires the trigger on Posts, which writes to AuditPosts */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;merge_matched_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;merge_not_matched_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;merge_output&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MERGE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MERGE: Where Reality Never Lives Up To Expectations&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MINUTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MERGE: Where Reality Never Lives Up To Expectations&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MINUTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MATCHED&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MATCHED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AcceptedAnswerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FavoriteCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test row inserted via MERGE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;test&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Merged Row&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OUTPUT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;merge_output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;merge_matched_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;merge_output&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UPDATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;merge_not_matched_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;merge_output&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INSERT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Step M (MERGE): &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;merge_matched_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; row(s) updated (WHEN MATCHED), &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;merge_not_matched_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; row(s) inserted (WHEN NOT MATCHED BY TARGET).&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step M */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step M:&amp;lt;/strong&amp;gt; MERGE statement&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Dynamic SQL with sp_executesql */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* This fires the trigger on Posts via DELETE, which writes to AuditPosts */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Delete the row that Step M (MERGE statement) modified - MERGE always creates or updates a row */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Find the row with the most recent LastActivityDate that was updated in the last minute */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;posts_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;posts_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MINUTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastActivityDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MINUTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;posts_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;posts_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dynamic SQL DELETE (Step N) did not find a row to delete. Expected at least one row with LastActivityDate updated by Step M (MERGE statement) in the last minute.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; DELETE /* run via dynamic sql */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; p
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; FROM dbo.Posts AS p
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; WHERE p.Id = @posts_id;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@posts_id integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;posts_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Capture Query Store after Step N */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;strong&amp;gt;Step N:&amp;lt;/strong&amp;gt; Dynamic SQL DELETE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The test procedure performs the following operations in order:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;INSERT 10 rows&lt;/td&gt;
&lt;td&gt;Single INSERT statement with VALUES clause inserting 5 questions (PostTypeId=1) and 5 answers (PostTypeId=2)&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate (10 times), adds 4 rows to AuditPosts per row (Action=&amp;lsquo;I&amp;rsquo;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;UPDATE Question 1&lt;/td&gt;
&lt;td&gt;Updates Title column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate, adds 4 rows to AuditPosts (Action=&amp;lsquo;U&amp;rsquo; - Title is monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;UPDATE Question 2&lt;/td&gt;
&lt;td&gt;Updates CommentCount column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate only (CommentCount not monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;UPDATE Question 3&lt;/td&gt;
&lt;td&gt;Updates Body column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate only (Body not monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;UPDATE Question 4&lt;/td&gt;
&lt;td&gt;Updates LastEditDate column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate only (LastEditDate not monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;UPDATE Question 5&lt;/td&gt;
&lt;td&gt;Updates Score column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate, adds 4 rows to AuditPosts (Action=&amp;lsquo;U&amp;rsquo; - Score is monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;UPDATE Answer 1&lt;/td&gt;
&lt;td&gt;Updates OwnerUserId column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate, adds 4 rows to AuditPosts (Action=&amp;lsquo;U&amp;rsquo; - OwnerUserId is monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H&lt;/td&gt;
&lt;td&gt;UPDATE Answer 2&lt;/td&gt;
&lt;td&gt;Updates CommentCount column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate only (CommentCount not monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;UPDATE Answer 3&lt;/td&gt;
&lt;td&gt;Updates Body column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate only (Body not monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;J&lt;/td&gt;
&lt;td&gt;UPDATE Answer 4&lt;/td&gt;
&lt;td&gt;Updates LastEditDate column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate only (LastEditDate not monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;K&lt;/td&gt;
&lt;td&gt;UPDATE Answer 5&lt;/td&gt;
&lt;td&gt;Updates Score column&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate, adds 4 rows to AuditPosts (Action=&amp;lsquo;U&amp;rsquo; - Score is monitored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;DELETE 10 rows&lt;/td&gt;
&lt;td&gt;Single DELETE statement removing all 10 inserted rows&lt;/td&gt;
&lt;td&gt;Adds 4 rows to AuditPosts per row (Action=&amp;lsquo;D&amp;rsquo;), does not update LastActivityDate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;td&gt;MERGE statement&lt;/td&gt;
&lt;td&gt;MERGE operation that updates LastActivityDate if row exists, or inserts new row if not&lt;/td&gt;
&lt;td&gt;Updates LastActivityDate, adds 4 rows to AuditPosts (Action=&amp;lsquo;I&amp;rsquo; in this case - inserts new row)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Dynamic SQL DELETE&lt;/td&gt;
&lt;td&gt;DELETE statement executed via &lt;code&gt;sp_executesql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adds 4 rows to AuditPosts (Action=&amp;lsquo;D&amp;rsquo;), does not update LastActivityDate. Deletes row from Step M.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Steps overview:&lt;/strong&gt; A (INSERT 10 rows), B-K (10 individual UPDATEs), L (DELETE 10 rows), M (MERGE statement), N (Dynamic SQL DELETE)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trigger fires:&lt;/strong&gt; 14 total (1 INSERT statement, 10 UPDATE statements, 1 DELETE statement, 1 MERGE statement, 1 dynamic SQL DELETE statement). The trigger fires once per DML statement, not once per row.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LastActivityDate updates:&lt;/strong&gt; 21 total rows updated (10 rows from step A INSERT, 10 rows from steps B-K UPDATEs, 1 row from step M MERGE)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AuditPosts inserts:&lt;/strong&gt; 104 total rows (44 Action=&amp;lsquo;I&amp;rsquo; from steps A and M, 16 Action=&amp;lsquo;U&amp;rsquo; from steps B/F/G/K, 44 Action=&amp;lsquo;D&amp;rsquo; from steps L and N)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operations that update LastActivityDate:&lt;/strong&gt; All INSERT and UPDATE operations (steps A-K, M)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operations that don&amp;rsquo;t update LastActivityDate:&lt;/strong&gt; All DELETE operations (steps L, N) because DELETE operations don&amp;rsquo;t have an inserted table&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="run-test-procedure-and-review-audit-table-rows-inserted-by-trigger"&gt;Run Test Procedure and Review Audit Table Rows Inserted by Trigger&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s run the procedure and check the audit table:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ANSI_NULLS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTED_IDENTIFIER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ARITHABORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NUMERIC_ROUNDABORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IMPLICIT_TRANSACTIONS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_TestTriggerFires&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Review audit results */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;audit_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;posts_affected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Detailed view */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ActivityDate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ColumnName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Each run of &lt;code&gt;dbo.sp_TestTriggerFires&lt;/code&gt; should add 104 rows to &lt;code&gt;dbo.AuditPosts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;44 rows with Action = &amp;lsquo;I&amp;rsquo; (11 inserts × 4 columns each: 10 from &lt;code&gt;Step A&lt;/code&gt;, 1 from &lt;code&gt;Step M&lt;/code&gt; MERGE when it inserts)&lt;/li&gt;
&lt;li&gt;16 rows with Action = &amp;lsquo;U&amp;rsquo; (4 updates × 4 columns each: from &lt;code&gt;Steps B, F, G, K&lt;/code&gt; that change monitored columns)&lt;/li&gt;
&lt;li&gt;44 rows with Action = &amp;lsquo;D&amp;rsquo; (11 deletes × 4 columns each: 10 from &lt;code&gt;Step L&lt;/code&gt;, 1 from &lt;code&gt;Step N&lt;/code&gt; dynamic SQL DELETE)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="review-query-store-data"&gt;Review Query Store Data&lt;/h2&gt;
&lt;p&gt;Since we captured Query Store data after each step in the &lt;code&gt;dbo.QueryStoreHistory&lt;/code&gt; table, we can analyze what changed between steps.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Summary: final state for each unique query_id and context_settings_id combination */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Only show IMPLICIT_TRANSACTIONS since that&amp;#39;s the key difference */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;implicit_transactions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%IMPLICIT_TRANSACTIONS ON%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ON&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OFF&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Summarize query text to identify trigger operations */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_summary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%UPDATE%LastActivityDate%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UPDATE LastActivityDate&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%INSERT INTO%dbo.AuditPosts%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Action = &amp;#39;&amp;#39;I&amp;#39;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INSERT INTO AuditPosts (Action=I)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%INSERT INTO%dbo.AuditPosts%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Action = &amp;#39;&amp;#39;U&amp;#39;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INSERT INTO AuditPosts (Action=U)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%INSERT INTO%dbo.AuditPosts%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Action = &amp;#39;&amp;#39;D&amp;#39;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INSERT INTO AuditPosts (Action=D)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* List only steps where execution count increased, in order, with execution counts */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;steps_used&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING_AGG&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executions_added&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executions_added&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; exec&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; execs&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WITHIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Sum execution counts across all plans for the latest step */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh_final&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_final&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_final&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_final&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_final&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_step_number&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_compiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_count_compiles&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get latest state for each query_id and context_settings_id */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_count_compiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Get only steps where execution count increased - aggregate by step_number first, summing across all plans */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_count_executions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Calculate executions added in this step */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executions_added&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Aggregate by step_number, summing execution counts across all plans */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_description&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get previous step&amp;#39;s total execution count (summed across all plans) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Get the immediately previous step (highest step_number &amp;lt; current step) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OUTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsh_prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_prev&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsh_prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_number&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_step&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Only include steps where execution count increased (or first appearance) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev_step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_count_executions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step_list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options_decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_step_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_count_compiles&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_executions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_compiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_settings_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This summary shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only steps where execution count increased for each query_id (&lt;code&gt;steps_used&lt;/code&gt;), listed in order&lt;/li&gt;
&lt;li&gt;Final execution and compile counts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the actual Query Store output from running the test procedure. Look for how query IDs are split by context settings and which steps use each query ID:&lt;/p&gt;
&lt;div class="table-responsive"&gt;
&lt;table style="font-size: 0.9em; border-collapse: collapse; width: 100%;"&gt;
&lt;thead&gt;
&lt;tr style="border-bottom: 2px solid rgba(70, 127, 191, 0.15);"&gt;
&lt;th style="text-align: left; padding: 8px; font-weight: 600;"&gt;query id (context settings id)&lt;/th&gt;
&lt;th style="text-align: left; padding: 8px; font-weight: 600;"&gt;implicit transaction?&lt;/th&gt;
&lt;th style="text-align: left; padding: 8px; font-weight: 600;"&gt;query summary&lt;/th&gt;
&lt;th style="text-align: left; padding: 8px; font-weight: 600;"&gt;steps used&lt;/th&gt;
&lt;th style="text-align: left; padding: 8px; font-weight: 600;"&gt;total executions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;3 (2)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;OFF&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;UPDATE LastActivityDate&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step A:&lt;/strong&gt; INSERT 10 rows (1 exec), &lt;strong&gt;Step L:&lt;/strong&gt; DELETE 10 rows (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;4 (2)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;OFF&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=I)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step A:&lt;/strong&gt; INSERT 10 rows (1 exec), &lt;strong&gt;Step L:&lt;/strong&gt; DELETE 10 rows (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;5 (2)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;OFF&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=U)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step A:&lt;/strong&gt; INSERT 10 rows (1 exec), &lt;strong&gt;Step L:&lt;/strong&gt; DELETE 10 rows (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;6 (2)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;OFF&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=D)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step A:&lt;/strong&gt; INSERT 10 rows (1 exec), &lt;strong&gt;Step L:&lt;/strong&gt; DELETE 10 rows (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;12 (7)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;UPDATE LastActivityDate&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step B:&lt;/strong&gt; UPDATE Question 1 (Title) (1 exec), &lt;strong&gt;Step C:&lt;/strong&gt; UPDATE Question 2 (CommentCount) (1 exec), &lt;strong&gt;Step D:&lt;/strong&gt; UPDATE Question 3 (Body) (1 exec), &lt;strong&gt;Step E:&lt;/strong&gt; UPDATE Question 4 (LastEditDate) (1 exec), &lt;strong&gt;Step F:&lt;/strong&gt; UPDATE Question 5 (Score) (1 exec), &lt;strong&gt;Step G:&lt;/strong&gt; UPDATE Answer 1 (OwnerUserId) (1 exec), &lt;strong&gt;Step H:&lt;/strong&gt; UPDATE Answer 2 (CommentCount) (1 exec), &lt;strong&gt;Step I:&lt;/strong&gt; UPDATE Answer 3 (Body) (1 exec), &lt;strong&gt;Step J:&lt;/strong&gt; UPDATE Answer 4 (LastEditDate) (1 exec), &lt;strong&gt;Step K:&lt;/strong&gt; UPDATE Answer 5 (Score) (1 exec), &lt;strong&gt;Step N:&lt;/strong&gt; Dynamic SQL DELETE (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;13 (7)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=I)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step B:&lt;/strong&gt; UPDATE Question 1 (Title) (1 exec), &lt;strong&gt;Step C:&lt;/strong&gt; UPDATE Question 2 (CommentCount) (1 exec), &lt;strong&gt;Step D:&lt;/strong&gt; UPDATE Question 3 (Body) (1 exec), &lt;strong&gt;Step E:&lt;/strong&gt; UPDATE Question 4 (LastEditDate) (1 exec), &lt;strong&gt;Step F:&lt;/strong&gt; UPDATE Question 5 (Score) (1 exec), &lt;strong&gt;Step G:&lt;/strong&gt; UPDATE Answer 1 (OwnerUserId) (1 exec), &lt;strong&gt;Step H:&lt;/strong&gt; UPDATE Answer 2 (CommentCount) (1 exec), &lt;strong&gt;Step I:&lt;/strong&gt; UPDATE Answer 3 (Body) (1 exec), &lt;strong&gt;Step J:&lt;/strong&gt; UPDATE Answer 4 (LastEditDate) (1 exec), &lt;strong&gt;Step K:&lt;/strong&gt; UPDATE Answer 5 (Score) (1 exec), &lt;strong&gt;Step N:&lt;/strong&gt; Dynamic SQL DELETE (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;14 (7)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=U)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step B:&lt;/strong&gt; UPDATE Question 1 (Title) (1 exec), &lt;strong&gt;Step C:&lt;/strong&gt; UPDATE Question 2 (CommentCount) (1 exec), &lt;strong&gt;Step D:&lt;/strong&gt; UPDATE Question 3 (Body) (1 exec), &lt;strong&gt;Step E:&lt;/strong&gt; UPDATE Question 4 (LastEditDate) (1 exec), &lt;strong&gt;Step F:&lt;/strong&gt; UPDATE Question 5 (Score) (1 exec), &lt;strong&gt;Step G:&lt;/strong&gt; UPDATE Answer 1 (OwnerUserId) (1 exec), &lt;strong&gt;Step H:&lt;/strong&gt; UPDATE Answer 2 (CommentCount) (1 exec), &lt;strong&gt;Step I:&lt;/strong&gt; UPDATE Answer 3 (Body) (1 exec), &lt;strong&gt;Step J:&lt;/strong&gt; UPDATE Answer 4 (LastEditDate) (1 exec), &lt;strong&gt;Step K:&lt;/strong&gt; UPDATE Answer 5 (Score) (1 exec), &lt;strong&gt;Step N:&lt;/strong&gt; Dynamic SQL DELETE (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;15 (7)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=D)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step B:&lt;/strong&gt; UPDATE Question 1 (Title) (1 exec), &lt;strong&gt;Step C:&lt;/strong&gt; UPDATE Question 2 (CommentCount) (1 exec), &lt;strong&gt;Step D:&lt;/strong&gt; UPDATE Question 3 (Body) (1 exec), &lt;strong&gt;Step E:&lt;/strong&gt; UPDATE Question 4 (LastEditDate) (1 exec), &lt;strong&gt;Step F:&lt;/strong&gt; UPDATE Question 5 (Score) (1 exec), &lt;strong&gt;Step G:&lt;/strong&gt; UPDATE Answer 1 (OwnerUserId) (1 exec), &lt;strong&gt;Step H:&lt;/strong&gt; UPDATE Answer 2 (CommentCount) (1 exec), &lt;strong&gt;Step I:&lt;/strong&gt; UPDATE Answer 3 (Body) (1 exec), &lt;strong&gt;Step J:&lt;/strong&gt; UPDATE Answer 4 (LastEditDate) (1 exec), &lt;strong&gt;Step K:&lt;/strong&gt; UPDATE Answer 5 (Score) (1 exec), &lt;strong&gt;Step N:&lt;/strong&gt; Dynamic SQL DELETE (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;27 (10)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;UPDATE LastActivityDate&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;28 (10)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=I)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;29 (10)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=U)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;30 (10)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=D)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;31 (11)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;UPDATE LastActivityDate&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;32 (11)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=I)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;33 (11)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=U)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="border-bottom: 1px solid rgba(70, 127, 191, 0.08);"&gt;
&lt;td style="padding: 8px;"&gt;34 (11)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;ON&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;INSERT INTO AuditPosts (Action=D)&lt;/td&gt;
&lt;td style="padding: 8px; word-wrap: break-word;"&gt;&lt;strong&gt;Step M:&lt;/strong&gt; MERGE statement (1 exec)&lt;/td&gt;
&lt;td style="padding: 8px;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Observations from the Query Store data:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Separate query_ids for different trigger operations&lt;/strong&gt;: The same DML statement (e.g., INSERT 10 rows in Step A) appears across multiple query_ids (3, 4, 5, 6), each representing a different trigger operation type:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query ID 3: UPDATE LastActivityDate&lt;/li&gt;
&lt;li&gt;Query ID 4: INSERT INTO AuditPosts with Action=&amp;lsquo;I&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Query ID 5: INSERT INTO AuditPosts with Action=&amp;lsquo;U&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Query ID 6: INSERT INTO AuditPosts with Action=&amp;lsquo;D&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This matches the trigger&amp;rsquo;s structure: it contains separate SQL statements for each operation type (one UPDATE for LastActivityDate, and separate INSERT statements for Action=&amp;lsquo;I&amp;rsquo;, &amp;lsquo;U&amp;rsquo;, and &amp;lsquo;D&amp;rsquo;). Because the trigger uses no safety checks (no IF EXISTS blocks), all these statements are always present and execute based on their WHERE clause conditions (&lt;code&gt;WHERE NOT EXISTS (SELECT 1/0 FROM deleted AS d)&lt;/code&gt; for INSERT operations, ISNULL comparisons for UPDATE operations, &lt;code&gt;LEFT JOIN inserted ... WHERE i.Id IS NULL&lt;/code&gt; for DELETE operations), rather than being conditionally executed via IF statements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important note about Query Store execution counts:&lt;/strong&gt; Query Store counts all statement executions in the trigger, even when WHERE clauses match 0 rows. For example, Query ID 3 (UPDATE LastActivityDate) shows execution during Step L DELETE, but this UPDATE affects 0 rows because it joins to the &lt;code&gt;inserted&lt;/code&gt; table which is empty during DELETE operations. Query Store tracks the execution, but the statement does no actual work. This is why the test summary correctly notes that DELETE operations don&amp;rsquo;t update LastActivityDate, even though Query Store shows executions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Multiple context settings created&lt;/strong&gt;: Even though we didn&amp;rsquo;t vary user settings, Query Store created 4 different &lt;code&gt;context_settings_id&lt;/code&gt; values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;context_settings_id = 2&lt;/code&gt; (IMPLICIT_TRANSACTIONS OFF): Used for Step A (INSERT 10 rows) and Step L (DELETE 10 rows)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;context_settings_id = 7&lt;/code&gt; (IMPLICIT_TRANSACTIONS ON): Used for Steps B-K and N (individual UPDATEs and dynamic SQL DELETE)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;context_settings_id = 10&lt;/code&gt; (IMPLICIT_TRANSACTIONS ON): Used for Step M (MERGE statement)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;context_settings_id = 11&lt;/code&gt; (IMPLICIT_TRANSACTIONS ON): Also used for Step M (MERGE statement)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Interestingly, the MERGE statement (Step M) appears with two different context_settings_id values (10 and 11), both showing IMPLICIT_TRANSACTIONS ON. This happens even though we didn&amp;rsquo;t change SET options between operations. The MERGE fires the trigger twice (once for the UPDATE action, once for the INSERT action), and Query Store assigns different context_settings_id values to each trigger execution from that single MERGE statement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The same DML statement creates multiple query_ids (one per trigger operation) and multiple context_settings_id values, even when you don&amp;rsquo;t change any settings. Data ends up spread across all these query_ids and context settings, so it&amp;rsquo;s easy to miss executions if your queries don&amp;rsquo;t aggregate across everything.&lt;/p&gt;
&lt;h2 id="xevents-event-file-session-on-sqlservermodule_start"&gt;XEvents Event File Session on sqlserver.module_start&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create an Extended Events session to capture when the trigger module starts. This approach is based on &lt;a href="https://dba.stackexchange.com/a/327968/471"&gt;Tomáš Zíka&amp;rsquo;s answer&lt;/a&gt; from &lt;a href="https://straightforwardsql.com/"&gt;straightforwardsql.com&lt;/a&gt;, using &lt;code&gt;sqlserver.module_start&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is created with &lt;code&gt;MAX_DISPATCH_LATENCY = 5 SECONDS&lt;/code&gt; for convenience in testing, for production code you generally want to use a longer amount.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Drop if exists and create idempotent session */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_module_start&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module_start&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tsql_stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StackOverflow2013&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_module_start.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="xevents-event-file-session-on-sqlservermodule_end"&gt;XEvents Event File Session on sqlserver.module_end&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s also create an Extended Events session to capture when the trigger module ends. Unless you are concerned about lookign for trigger failures, this is arguably more useful than &lt;code&gt;module_start&lt;/code&gt;, as it allows us to capture duration and row_count metrics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is created with &lt;code&gt;MAX_DISPATCH_LATENCY = 5 SECONDS&lt;/code&gt; for convenience in testing, for production code you generally want to use a longer amount.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Drop if exists and create idempotent session */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_module_end&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module_end&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tsql_stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StackOverflow2013&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_module_end.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="xevents-event-file-session-on-stored-procedure-statement-completions"&gt;XEvents Event File Session on Stored Procedure Statement Completions&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s create a session to capture statement completions within the trigger. We&amp;rsquo;ll capture &lt;code&gt;sp_statement_completed&lt;/code&gt; filtered to only the trigger object to see which statements execute inside the trigger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To filter &lt;code&gt;sp_statement_completed&lt;/code&gt; events by object name, you must include &lt;code&gt;SET collect_object_name = (1)&lt;/code&gt; in the event definition. When efficiency is important, filter on &lt;code&gt;object_id&lt;/code&gt; instead of &lt;code&gt;object_name&lt;/code&gt; (object_id is always available and doesn&amp;rsquo;t require the collect_object_name setting).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is created with &lt;code&gt;MAX_DISPATCH_LATENCY = 5 SECONDS&lt;/code&gt; for convenience in testing, for production code you generally want to use a longer amount.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_completions&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_completions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_completions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_completions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_statement_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collect_object_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StackOverflow2013&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_completions.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_completions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="xevents-histogram-session-on-sp_statement_completed"&gt;XEvents Histogram Session on sp_statement_completed&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s create a histogram session that tracks statement executions within the trigger. This histogram counts executions per unique statement, giving us an aggregated view of which statements execute most frequently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This uses a synchronous target (histogram) rather than an asynchronous target (event_file), so it aggregates data in memory rather than writing individual events to disk.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_statement_histogram&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_statement_histogram&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_statement_histogram&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_statement_histogram&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_statement_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collect_object_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StackOverflow2013&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;histogram&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filtering_event_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sqlserver.sp_statement_completed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;object_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_statement_histogram&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="run-our-test-procedure-again-then-query-all-trace-files"&gt;Run our Test Procedure Again, Then Query All Trace Files&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s run our test procedure again and query the Extended Events data.&lt;/p&gt;
&lt;p&gt;Because the Extended Events session is configured with &lt;code&gt;MAX_DISPATCH_LATENCY = 5 SECONDS&lt;/code&gt;, we wait 5 seconds after running the test procedure before querying the trace files.&lt;/p&gt;
&lt;h2 id="run-test-procedure"&gt;Run Test Procedure&lt;/h2&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Run test - audit table will accumulate rows from all runs */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Ensure consistent SET options for Query Store tracking */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ANSI_NULLS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTED_IDENTIFIER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ARITHABORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NUMERIC_ROUNDABORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IMPLICIT_TRANSACTIONS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_TestTriggerFires&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Because the Extended Events session is configured with MAX_DISPATCH_LATENCY = 5 SECONDS, we need to wait at least 5 seconds after running the test procedure before querying the trace files. This ensures events have been flushed from the buffer to disk.&lt;/p&gt;
&lt;h2 id="query-module_start-events"&gt;Query module_start Events&lt;/h2&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@name)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(50)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@timestamp)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_id&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calling_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;sql_text&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tsql_stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;tsql_stack&amp;#34;]/value)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client_app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;client_app_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;session_id&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;username&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;full_event_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_xe_file_target_read_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_module_start*.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@timestamp)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note:&lt;/strong&gt; The query includes the &lt;code&gt;tsql_stack&lt;/code&gt; action which contains the call stack with &lt;code&gt;sql_handle&lt;/code&gt; values that can be used to identify the DML statement that fired the trigger. To parse the &lt;code&gt;tsql_stack&lt;/code&gt; and retrieve statement text from the plan cache, see &lt;a href="https://dba.stackexchange.com/a/327968/471"&gt;Tomáš Zíka's answer&lt;/a&gt; on Stack Overflow for detailed instructions.
&lt;/div&gt;
&lt;h2 id="query-module_end-events"&gt;Query module_end Events&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Module_end&lt;/code&gt; events have &lt;code&gt;duration&lt;/code&gt; and &lt;code&gt;row_count&lt;/code&gt; columns, so those are included here. &lt;code&gt;Duration&lt;/code&gt; is in microseconds on SQL Server 2025.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@name)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(50)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@timestamp)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_id&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;duration&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;row_count&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calling_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;sql_text&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tsql_stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;tsql_stack&amp;#34;]/value)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client_app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;client_app_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;session_id&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;username&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;full_event_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_xe_file_target_read_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_module_end*.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@timestamp)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="query-completion-events---sp_statement_completed-for-trigger-statements"&gt;Query Completion Events - sp_statement_Completed for Trigger Statements&lt;/h2&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@name)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(50)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@timestamp)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;duration&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;duration_microseconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;cpu_time&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu_time_microseconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;logical_reads&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;statement&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statement_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;sql_text&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;database_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_id&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client_app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;client_app_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;session_id&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;username&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;full_event_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_xe_file_target_read_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_completions*.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_timestamp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="query-aggregate-sp_statement_completed-events"&gt;Query Aggregate sp_statement_completed Events&lt;/h2&gt;
&lt;p&gt;To get aggregated metrics like total CPU time and total logical reads per statement, query the event_file target from trigger_completions and aggregate.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statement_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_cpu_time_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpu_time_microseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_cpu_time_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpu_time_microseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_duration_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration_microseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_duration_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration_microseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statement_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;statement&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu_time_microseconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;cpu_time&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;logical_reads&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;duration_microseconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;duration&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_xe_file_target_read_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\trigger_completions*.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statement_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statement_text&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_cpu_time_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="query-histogram-target-for-statement-execution-counts"&gt;Query histogram Target for Statement Execution Counts&lt;/h2&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statement_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(@count)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_session_targets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xst&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_session_address&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_statement_histogram&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;histogram&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;histogram_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;//HistogramTarget/Slot&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;histogram_slots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(@count)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="extended-events-observations"&gt;Extended Events Observations&lt;/h2&gt;
&lt;p&gt;Comparing Extended Events data with the audit table and Query Store:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trigger execution counts:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Extended Events &lt;code&gt;module_start&lt;/code&gt; and &lt;code&gt;module_end&lt;/code&gt; captured 15 trigger executions, even though the test procedure executed only 14 DML statements. The discrepancy comes from MERGE: as &lt;a href="https://dba.stackexchange.com/a/328057/471"&gt;Paul White explains&lt;/a&gt;, MERGE can fire triggers multiple times—once for each action type (INSERT, UPDATE, DELETE) that executes. Our MERGE statement (Step M) performs both an INSERT (WHEN NOT MATCHED BY TARGET) and an UPDATE (WHEN MATCHED), so the trigger fires twice for that single MERGE statement.&lt;/p&gt;
&lt;p&gt;Query Store execution counts align with this when aggregated across all query_ids and context_settings_id values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query IDs 3-6 (context_settings_id 2): 2 executions total (Step A INSERT + Step L DELETE)&lt;/li&gt;
&lt;li&gt;Query IDs 12-15 (context_settings_id 7): 11 executions total (Steps B-K individual UPDATEs + Step N dynamic SQL DELETE)&lt;/li&gt;
&lt;li&gt;Query IDs 27-34 (context_settings_id 10, 11): 2 executions total (Step M MERGE fires trigger twice, creating two different context_settings_id values)&lt;/li&gt;
&lt;li&gt;Total: 2 + 11 + 2 = 15 trigger executions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Statement-level vs query-level granularity:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Extended Events &lt;code&gt;sp_statement_completed&lt;/code&gt; captured 75 individual statement executions within the trigger. This is statement-level detail—each SQL statement that executed inside the trigger, not the trigger executions themselves. Each trigger execution contains multiple statements (SET NOCOUNT ON, UPDATE LastActivityDate, INSERT INTO AuditPosts statements).&lt;/p&gt;
&lt;p&gt;Query Store tracks query-level executions aggregated by query_id and context_settings_id. The same trigger operation (like &amp;ldquo;UPDATE LastActivityDate&amp;rdquo;) appears across multiple query_ids depending on context settings, requiring careful aggregation to get accurate counts.&lt;/p&gt;
&lt;p&gt;The histogram target shows execution counts per unique statement, matching the event_file counts when grouped by statement text.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Row-level results:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The audit table shows 104 rows inserted—this is row-level detail, a different granularity entirely from both Extended Events statement counts and Query Store query counts.&lt;/p&gt;
&lt;h2 id="cleanup"&gt;Cleanup&lt;/h2&gt;
&lt;p&gt;This script tidies everything up:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Stop and drop Extended Events sessions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_module_start&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_module_end&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_module_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_completions&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_completions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_completions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;trigger_statement_histogram&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_statement_histogram&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trigger_statement_histogram&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Clean up test objects */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.tr_Posts_Audit_No_Safeties&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRIGGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tr_Posts_Audit_No_Safeties&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.sp_TestTriggerFires&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_TestTriggerFires&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.sp_CaptureQueryStoreHistory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_CaptureQueryStoreHistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.QueryStoreHistory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStoreHistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.AuditPosts&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuditPosts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="what-we-observed-about-tracing-trigger-executions"&gt;What We Observed About Tracing Trigger Executions&lt;/h2&gt;
&lt;p&gt;Both Query Store and Extended Events can trace trigger executions, but they work at different levels of detail and have different strengths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Query Store&lt;/strong&gt; tracks query-level executions, which means trigger code gets split across multiple query_ids (one per SQL statement in the trigger). The same DML statement can create multiple query_ids and context_settings_id values, even when you don&amp;rsquo;t change any session settings. You need to aggregate across all query_ids and context settings to get accurate execution counts. The upside is that Query Store automatically captures execution plans, runtime statistics, and performance metrics without any additional setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extended Events&lt;/strong&gt; gives you more control over what you capture. The &lt;code&gt;sqlserver.module_start&lt;/code&gt; event captures each time the trigger module starts executing, giving you a clean count of trigger executions. The &lt;code&gt;sp_statement_completed&lt;/code&gt; event captures individual statement executions within the trigger, showing you exactly which statements ran and their performance metrics. Extended Events requires more setup and configuration, but it provides statement-level detail that Query Store doesn&amp;rsquo;t expose directly.&lt;/p&gt;
&lt;p&gt;To filter &lt;code&gt;sp_statement_completed&lt;/code&gt; events by object name, you must include &lt;code&gt;SET collect_object_name = (1)&lt;/code&gt; in the event definition. For better performance, you can filter on &lt;code&gt;object_id&lt;/code&gt; instead of &lt;code&gt;object_name&lt;/code&gt; (object_id is always available and doesn&amp;rsquo;t require the collect_object_name setting).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key differences we found:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Execution counts&lt;/strong&gt;: Extended Events &lt;code&gt;module_start&lt;/code&gt; showed 15 trigger executions, which matched Query Store&amp;rsquo;s aggregated counts once we accounted for MERGE firing the trigger twice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Granularity&lt;/strong&gt;: Extended Events &lt;code&gt;sp_statement_completed&lt;/code&gt; captured 75 individual statement executions within the trigger, while Query Store tracked query-level executions aggregated by query_id. The audit table showed 104 rows inserted, which is yet another level of detail (row-level results).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data organization&lt;/strong&gt;: Query Store data spreads across multiple query_ids and context_settings_id values, making it easy to miss executions if your queries don&amp;rsquo;t aggregate properly. Extended Events gives you event-level data that&amp;rsquo;s easier to filter and analyze, but requires more manual setup.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For tracing trigger executions, Extended Events provides cleaner, more direct counts and statement-level detail. Query Store works well for performance analysis of the queries within triggers, but requires careful aggregation to get accurate execution counts.&lt;/p&gt;</description></item><item><title>Static Site Improvements: Scheduled Posts, Preview Builds, Robots Writing the CSS</title><link>https://kendralittle.com/2025/12/22/static-site-workflows-that-work-scheduled-posts-preview-builds-robots-writing-css/</link><pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/12/22/static-site-workflows-that-work-scheduled-posts-preview-builds-robots-writing-css/</guid><description>&lt;p&gt;I&amp;rsquo;ve standardized design, upgraded components, added client-side search, and configured browser caching for this site over the last few weeks. I&amp;rsquo;ve also adopted a workflow that helps me capture ideas, test changes, and get posts published more easily.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a web developer, I&amp;rsquo;m a database nerd. I&amp;rsquo;m don&amp;rsquo;t &lt;strong&gt;want&lt;/strong&gt; to be great at CSS. I got this all done with a personal &lt;a href="https://cursor.sh/"&gt;Cursor&lt;/a&gt; subscription and an obsessive urge to tag and tidy all my old posts. AI tooling these days makes static websites easier than ever to set up, design, and improve.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re open to AI tooling and want to create a website (or upgrade one you already have), a static site is a great bet.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Related posts&lt;/strong&gt;: I've written about my static site journey before. Check out &lt;a href="https://kendralittle.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/"&gt;Moving From WordPress to an Azure Static Site with Hugo&lt;/a&gt; for my migration story, and &lt;a href="https://kendralittle.com/2023/06/29/adding-netlify-contact-form-hugo-mainroad/"&gt;Adding a Netlify Contact Form to a Hugo Static Site&lt;/a&gt; for details on moving to Netlify.
&lt;/div&gt;
&lt;h2 id="recap-of-my-site-setup"&gt;Recap of My Site Setup&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/css.jpg" width="260"&gt;
&lt;/figure&gt;
&lt;p&gt;KendraLittle.com is a static site built with &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, a static site generator. I write posts in Markdown, Hugo builds them into HTML files, and &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt; hosts and deploys the site. There&amp;rsquo;s no database, no server-side code, and no Content Management System, just files in a free &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; repository and Netlify.&lt;/p&gt;
&lt;p&gt;I currently pay for a Netlify subscription and a Cursor subscription. It&amp;rsquo;s a hobby for me, I want some fun things, so those costs are worth it to me. (Netlify has a good free tier, but occasionally I&amp;rsquo;m lucky enough to exceed its bandwidth costs. And I feel like I get good value for what I pay for.)&lt;/p&gt;
&lt;p&gt;This setup works well for a technical blog. It&amp;rsquo;s fast, secure, and easy to maintain.&lt;/p&gt;
&lt;p&gt;And I have &lt;strong&gt;never&lt;/strong&gt; missed WordPress.&lt;/p&gt;
&lt;h2 id="component-upgrades"&gt;Component Upgrades&lt;/h2&gt;
&lt;p&gt;I upgraded the major frontend components to bring the site up to date:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;&lt;/strong&gt;: Upgraded from 3.3.7 to 5.3.3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hugo&lt;/strong&gt;: Upgraded from 0.124.1 to 0.152.2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Hugo upgrade here was a big deal. There were some important fixes between those two versions, and I&amp;rsquo;d struggled to do this upgrade on my own before. I knew it was important to complete this before making more changes.&lt;/p&gt;
&lt;p&gt;These upgrades required template changes. Bootstrap 5 changed class names (&lt;code&gt;navbar-toggle&lt;/code&gt; → &lt;code&gt;navbar-toggler&lt;/code&gt;, &lt;code&gt;data-toggle&lt;/code&gt; → &lt;code&gt;data-bs-toggle&lt;/code&gt;). Hugo 0.152.2 deprecated some template functions, so I updated those too. Cursor helped identify all the places that needed changes, which made the upgrade process manageable.&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t bad this time at all, especially with the help of&amp;hellip;&lt;/p&gt;
&lt;h2 id="preview-deployments"&gt;Preview Deployments&lt;/h2&gt;
&lt;p&gt;Every time I open a pull request or push a change to a branch with a pull request, Netlify creates a preview deployment. I can see how the site looks and behaves before merging to main. This is especially valuable for CSS changes: I can test button heights, spacing, and mobile layouts in a real deployment without affecting the live site.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s basically a staging environment that&amp;rsquo;s automatically created for every pull request, and you can access it on different devices. (This post is not sponsored by Netlify, but this database person sure loves a staging site. They include this in the free plan, by the way.)&lt;/p&gt;
&lt;h2 id="local-development-workflow"&gt;Local Development Workflow&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m currently using Windows for my personal nerdery, so I have a PowerShell script that runs Hugo with specific flags for local development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--disableFastRender&lt;/code&gt; to ensure CSS changes are visible immediately&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--noHTTPCache&lt;/code&gt; to prevent browser caching issues&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--buildFuture&lt;/code&gt; to preview future-dated posts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The script also syncs CSS files before starting the server and optionally builds the search index. These customizations make local development smoother: I can see CSS changes right away&amp;ndash; at least usually. Admittedly, there are some times when I still have to do a full build of the site to see changes and I don&amp;rsquo;t fully understand why, but it&amp;rsquo;s not yet been a big enough problem to dive into.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the Hugo command the script runs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo server --port &lt;span class="m"&gt;1313&lt;/span&gt; --bind 127.0.0.1 --poll 700ms --disableFastRender --noHTTPCache --buildFuture&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--poll&lt;/code&gt; flag helps with reliable file watching on Windows, and &lt;code&gt;--buildFuture&lt;/code&gt; lets me preview posts scheduled for future dates.&lt;/p&gt;
&lt;h2 id="standardized-buttons-and-forms"&gt;Standardized Buttons and Forms&lt;/h2&gt;
&lt;p&gt;Before, buttons and form fields had wildly inconsistent heights, padding, and styling. I had a hard time fixing it.&lt;/p&gt;
&lt;p&gt;I used Cursor to find all button definitions and help standardize them. This cut down on the repetitive work, and chatting with the robot helped me figure out how to troubleshoot visual issues in Firefox somewhat efficiently (well, sometimes).&lt;/p&gt;
&lt;p&gt;I standardized everything to a 38px height:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Buttons&lt;/strong&gt;: All buttons (navigation, forms, sidebars) are 38px tall with consistent padding&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Form fields&lt;/strong&gt;: All input fields, selects, and textareas match the 38px height&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation links&lt;/strong&gt;: Navbar links use the same 8px horizontal padding as buttons for visual consistency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It ain&amp;rsquo;t perfect, but it&amp;rsquo;s a lot better.&lt;/p&gt;
&lt;h2 id="mobile-improvements"&gt;Mobile Improvements&lt;/h2&gt;
&lt;p&gt;I added mobile optimizations for screens under 768px:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Touch targets&lt;/strong&gt;: Buttons and form fields meet the 44px minimum for easy tapping&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Font sizes&lt;/strong&gt;: Set to 16px minimum to prevent iOS auto-zoom on input focus&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation&lt;/strong&gt;: Fixed navbar visibility and mobile menu behavior&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layout&lt;/strong&gt;: Reduced padding and improved spacing for small screens&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typography&lt;/strong&gt;: Scaled headings appropriately for mobile readability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These changes make the site easier to use on phones and tablets.&lt;/p&gt;
&lt;h2 id="client-side-search-with-pagefind"&gt;Client-Side Search with Pagefind&lt;/h2&gt;
&lt;p&gt;I added &lt;a href="https://pagefind.app/"&gt;Pagefind&lt;/a&gt; for client-side search. It indexes the built HTML files and provides search entirely in the browser, no backend needed. &lt;a href="https://kendralittle.com/search/"&gt;Here&amp;rsquo;s my new search page&lt;/a&gt;, and there&amp;rsquo;s a search form in the footer, too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pagefind indexes the site after Hugo builds&lt;/li&gt;
&lt;li&gt;Search happens in the browser using the index files&lt;/li&gt;
&lt;li&gt;Results are sorted by date (most recent first)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why this works for static sites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No server-side search needed&lt;/li&gt;
&lt;li&gt;Fast search results (everything happens client-side)&lt;/li&gt;
&lt;li&gt;Works with static site hosting (no backend required)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="github-issues-for-blog-post-ideas-and-bugs"&gt;GitHub Issues for Blog Post Ideas and Bugs&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m now using &lt;a href="https://docs.github.com/en/issues"&gt;GitHub Issues&lt;/a&gt; to track bugs and planned blog posts.&lt;/p&gt;
&lt;p&gt;The most important thing about this is that I can quickly create a GitHub issue on my phone for a blog post idea, wherever I am when I think about it. Or I can screenshot a bug on the site and create an issue for that, then forget it for the moment.&lt;/p&gt;
&lt;p&gt;Years ago, when I was a part of &lt;a href="https://www.brentozar.com/archive/2012/10/tadah-welcome-brentozarcom/"&gt;Brent Ozar Unlimited&lt;/a&gt;, I had a big old list of blog post ideas in a shared GitHub repo with the team that I could pull from anytime I was in the mood to write. I loved it. It feels good to be getting back to that, even if it&amp;rsquo;s just me.&lt;/p&gt;
&lt;h2 id="automatic-issue-syncing"&gt;Automatic Issue Syncing&lt;/h2&gt;
&lt;p&gt;I created &lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks"&gt;git hooks&lt;/a&gt; that automatically sync GitHub issues to local markdown files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;post-checkout hook&lt;/strong&gt;: Syncs issues when you switch branches&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;post-merge hook&lt;/strong&gt;: Syncs issues after pulling or merging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The hooks run a Python script that fetches issue data from the &lt;a href="https://docs.github.com/en/rest"&gt;GitHub API&lt;/a&gt; and saves it to &lt;code&gt;issues/issue-{number}.md&lt;/code&gt;. This lets me reference issues locally without opening GitHub in a browser.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sure there are extensions and various other ways to do this, but I like markdown files, OK? My cursorrules file knows where my issues are, so I can also use prompts like, &amp;ldquo;new branch to write post in issue 29 to publish on Jan 10,&amp;rdquo; and it can get my workflow started and have an idea what basic things to put in the front matter of the new file it creates for me.&lt;/p&gt;
&lt;p&gt;I may switch this to a different mechanism than a git hook. Git is complex enough. But it&amp;rsquo;s good enough for now.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Front matter&lt;/strong&gt; is metadata at the top of a Markdown file, enclosed in &lt;code&gt;---&lt;/code&gt; markers. It contains information like the post title, date, categories, and tags. Hugo uses this metadata to generate the site structure and HTML.
&lt;/div&gt;
&lt;h2 id="standardizing-categories-and-tags"&gt;Standardizing Categories and Tags&lt;/h2&gt;
&lt;p&gt;I spent a good chunk of time cleaning up categories and tags across all my old blog posts. I had inconsistent taxonomy: tons of posts used &amp;ldquo;sql&amp;rdquo; as a category, many posts were missing tags entirely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I standardized:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Categories&lt;/strong&gt;: Established 9 main categories (like &lt;a href="https://kendralittle.com/categories/query-performance/"&gt;&lt;code&gt;query-performance&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://kendralittle.com/categories/indexing/"&gt;&lt;code&gt;indexing&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://kendralittle.com/categories/database-administration/"&gt;&lt;code&gt;database-administration&lt;/code&gt;&lt;/a&gt;) and moved old posts to the right categories. I also added &lt;a href="https://kendralittle.com/categories/azure-sql/"&gt;&lt;code&gt;azure-sql&lt;/code&gt;&lt;/a&gt; as a new category for cloud database content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tags&lt;/strong&gt;: Cleaned up generic tags and replaced them with specific technical terms. Each post now has 3-10 meaningful tags that reflect what&amp;rsquo;s actually in the content. You can now find all my love letters to &lt;a href="https://kendralittle.com/tags/azure-sql-managed-instance/"&gt;azure-sql-managed-instance&lt;/a&gt; all in one place.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Format&lt;/strong&gt;: Standardized everything to lowercase with hyphens (e.g., &lt;code&gt;query-store&lt;/code&gt; not &lt;code&gt;Query Store&lt;/code&gt; or &lt;code&gt;query_store&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was &lt;strong&gt;not&lt;/strong&gt; something that Cursor made super easy. I have 580+ posts at this point, and I didn&amp;rsquo;t feel like building a whole sentiment/content analysis machine. A few attempts to use python scripts to generate the tags didn&amp;rsquo;t go well, the tags were often ridiculous. Cursor doesn&amp;rsquo;t love going through that many posts manually, either.&lt;/p&gt;
&lt;p&gt;I worked through a fair amount of this while cooking things for Thanksgiving and doing other things. Not letting perfect be the enemy of good helped get me through it, and I&amp;rsquo;m pretty happy with where we landed.&lt;/p&gt;
&lt;h2 id="future-dated-posts-for-scheduling"&gt;Future-Dated Posts for Scheduling&lt;/h2&gt;
&lt;p&gt;Hugo supports future-dated posts. I can set a post&amp;rsquo;s date in the future, and Hugo won&amp;rsquo;t publish it until that date arrives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the date in a post&amp;rsquo;s front matter to a future date.&lt;/li&gt;
&lt;li&gt;Hugo won&amp;rsquo;t include the post in builds until after the build runs on a computer where it&amp;rsquo;s that date or later.&lt;/li&gt;
&lt;li&gt;Netlify automatically rebuilds KendraLittle.com daily (more on that next), so future posts publish automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s an example of front matter for a scheduled post:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;My Future Post&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ld"&gt;2026-01-10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a simple way to scheduling posts in advance. The static site generator (Hugo) handles the scheduling logic, and automated builds handle the publishing.&lt;/p&gt;
&lt;h2 id="netlify-automated-builds"&gt;Netlify Automated Builds&lt;/h2&gt;
&lt;p&gt;Netlify automatically builds and deploys the site when I push to the main branch. It also runs scheduled builds twice daily.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How scheduled builds work:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Netlify&amp;rsquo;s scheduled function (configured under &lt;code&gt;netlify/functions/&lt;/code&gt;) triggers at set times using a &lt;a href="https://crontab.guru/"&gt;cron&lt;/a&gt; schedule&lt;/li&gt;
&lt;li&gt;The function calls a &lt;a href="https://docs.netlify.com/configure-builds/build-hooks/"&gt;Netlify build hook&lt;/a&gt; URL, which triggers a new build&lt;/li&gt;
&lt;li&gt;Hugo builds the static site (including all posts with the date set to the current date or prior)&lt;/li&gt;
&lt;li&gt;Pagefind indexes the site for search&lt;/li&gt;
&lt;li&gt;Netlify deploys the result&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Setting up the build trigger:&lt;/strong&gt; I created a &lt;a href="https://docs.netlify.com/functions/scheduled-functions/"&gt;Netlify scheduled function&lt;/a&gt; that uses the &lt;a href="https://docs.netlify.com/functions/overview/"&gt;&lt;code&gt;@netlify/functions&lt;/code&gt;&lt;/a&gt; package&amp;rsquo;s &lt;code&gt;schedule&lt;/code&gt; helper. The function is configured with a cron expression in &lt;code&gt;netlify.toml&lt;/code&gt; and calls a build hook URL that Netlify generates. When you POST to that URL, it triggers a new deployment.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the scheduled function code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;node-fetch&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;@netlify/functions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BUILD_HOOK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://api.netlify.com/build_hooks/YOUR_HOOK_ID&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Runs twice daily: 11 AM UTC (6 AM EST) and 1 AM UTC (8 PM EST)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;0 11,1 * * *&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BUILD_HOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Deploy triggered successfully&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The cron expression &lt;code&gt;'0 11,1 * * *'&lt;/code&gt; runs at 11 AM UTC and 1 AM UTC daily. You configure this in &lt;code&gt;netlify.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduled-deploy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0 11,1 * * *&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="cache-headers"&gt;Cache Headers&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve configured &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"&gt;cache headers&lt;/a&gt; in &lt;code&gt;netlify.toml&lt;/code&gt; to improve performance. Static assets (CSS, JavaScript, images, fonts) are cached for 1 year with the &lt;code&gt;immutable&lt;/code&gt; flag: these files have versioned filenames from Hugo&amp;rsquo;s asset pipeline, so aggressive caching is safe. HTML files are cached for 1 hour with &lt;code&gt;must-revalidate&lt;/code&gt;, which balances performance with the need to show updated content.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the cache header configuration in &lt;code&gt;netlify.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Static assets - cache for 1 year (with versioning in filename)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/*.css&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Cache-Control&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;public, max-age=31536000, immutable&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/*.js&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Cache-Control&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;public, max-age=31536000, immutable&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/images/*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Cache-Control&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;public, max-age=31536000, immutable&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# HTML files - cache for 1 hour with revalidation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/*.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Cache-Control&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;public, max-age=3600, must-revalidate&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The site also uses a service worker for offline support and client-side caching. Initially, it was using &amp;ldquo;Cache First&amp;rdquo; for images even during local development, which meant updated images wouldn&amp;rsquo;t show up in preview until I cleared the browser cache. I updated the service worker to detect when it&amp;rsquo;s running on localhost and use &amp;ldquo;Network First&amp;rdquo; for images in development, so image updates appear immediately. In production, it still uses &amp;ldquo;Cache First&amp;rdquo; for better performance.&lt;/p&gt;
&lt;h2 id="want-to-build-your-own"&gt;Want to Build Your Own?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what I&amp;rsquo;m currently using and how to get started:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Core components:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;&lt;/strong&gt; (static site generator) - version 0.152.2&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/devcows/hugo-universal-theme"&gt;Universal theme&lt;/a&gt;&lt;/strong&gt; (Hugo theme - includes Bootstrap 5.3.3 via CDN)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://pagefind.app/"&gt;Pagefind&lt;/a&gt;&lt;/strong&gt; (client-side search - add after you have content)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hosting&lt;/strong&gt;: &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;, &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt;, or &lt;a href="https://pages.cloudflare.com/"&gt;Cloudflare Pages&lt;/a&gt; (all have free tiers)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Getting started:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new GitHub repository for your site&lt;/li&gt;
&lt;li&gt;Install Hugo: &lt;code&gt;brew install hugo&lt;/code&gt; (Mac) or &lt;code&gt;choco install hugo&lt;/code&gt; (Windows) or download from &lt;a href="https://gohugo.io/installation/"&gt;hugo.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Clone your repo and create a new site: &lt;code&gt;git clone &amp;lt;your-repo-url&amp;gt; &amp;amp;&amp;amp; cd &amp;lt;repo-name&amp;gt; &amp;amp;&amp;amp; hugo new site .&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.gitignore&lt;/code&gt; file with &lt;code&gt;public/&lt;/code&gt; and &lt;code&gt;.hugo_build.lock&lt;/code&gt; (Hugo generates these, don&amp;rsquo;t commit them)&lt;/li&gt;
&lt;li&gt;Choose a theme: Browse &lt;a href="https://themes.gohugo.io/"&gt;Hugo themes&lt;/a&gt;. To use the &lt;a href="https://github.com/devcows/hugo-universal-theme"&gt;Universal theme&lt;/a&gt;, I add it as a git submodule: &lt;code&gt;git submodule add https://github.com/devcows/hugo-universal-theme themes/universal&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Configure &lt;code&gt;config.toml&lt;/code&gt; with &lt;code&gt;theme = &amp;quot;universal&amp;quot;&lt;/code&gt; (or your chosen theme name)&lt;/li&gt;
&lt;li&gt;Create your first post: &lt;code&gt;hugo new blog/my-first-post.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run locally: &lt;code&gt;hugo server&lt;/code&gt; (view at &lt;code&gt;http://localhost:1313&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Commit and push: &lt;code&gt;git add . &amp;amp;&amp;amp; git commit -m &amp;quot;Initial Hugo site&amp;quot; &amp;amp;&amp;amp; git push&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Deploy: Choose a hosting option (all have free tiers):&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;&lt;/strong&gt;: Connect the repo in Netlify (includes preview deployments for pull requests)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt;&lt;/strong&gt;: Enable Pages in your repo settings and configure GitHub Actions to build and deploy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://pages.cloudflare.com/"&gt;Cloudflare Pages&lt;/a&gt;&lt;/strong&gt;: Free hosting with global CDN and automatic deployments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://gohugo.io/documentation/"&gt;Hugo documentation&lt;/a&gt; is excellent, and the Universal theme has good examples to get you started. Add Pagefind for search after you have content, and customize from there.&lt;/p&gt;
&lt;h2 id="what-about-jekyll"&gt;What About Jekyll?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; is another popular static site generator, and it&amp;rsquo;s the default for GitHub Pages. The main difference is that Jekyll is Ruby-based while Hugo is Go-based. Jekyll has a larger plugin ecosystem, while Hugo uses Go templates. Jekyll has big fans and a huge community. I&amp;rsquo;ve experimented with it recently on a new site and I really like it.&lt;/p&gt;
&lt;p&gt;For now, I&amp;rsquo;m resisting the urge to give this site a Jekyll makeover, but if it still seems like a fun idea in a couple of months I may give it a shot.&lt;/p&gt;</description></item><item><title>How to Filter RPC_Completed Events in Extended Events: SQL Server Guide</title><link>https://kendralittle.com/2025/12/15/how-to-filter-rpc-completed-events-extended-events/</link><pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/12/15/how-to-filter-rpc-completed-events-extended-events/</guid><description>&lt;p&gt;The &lt;code&gt;rpc_completed&lt;/code&gt; event in &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/extended-events/extended-events"&gt;Extended Events&lt;/a&gt; is useful when troubleshooting SQL Server performance. It captures detailed information about Remote Procedure Calls: that means stored procedure executions, including the calls to &lt;code&gt;sp_executesql&lt;/code&gt; often used by applications (including Entity Framework) to run parameterized queries against SQL Server. The output for &lt;code&gt;rpc_completed&lt;/code&gt; includes the parameters that were specified along with values provided, and the CPU time, logical reads, and duration used by the query.&lt;/p&gt;
&lt;p&gt;It can be frustrating to figure out how to filter this in Extended Events. Struggling with this is one of the primary reasons I sometimes use &lt;a href="https://learn.microsoft.com/en-us/sql/tools/sql-server-profiler/sql-server-profiler"&gt;ye Olde Profiler&lt;/a&gt; for initial investigations and to speedily observe something in SQL Server.&lt;/p&gt;
&lt;p&gt;Here is my survival guide to filtering &lt;code&gt;rpc_completed&lt;/code&gt;, which makes using XEvents suck less.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Filter.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="surely-chatgpt-or-claude-make-scripting-this-easier"&gt;Surely ChatGPT or Claude Make Scripting this Easier?&lt;/h2&gt;
&lt;p&gt;As of this writing, they aren&amp;rsquo;t great at scripting Extended Event sessions with working filters. As I&amp;rsquo;ll dig into below, a lot of details of Extended Events aren&amp;rsquo;t documented clearly, the user is left to query them from a SQL Server instance. LLMs do what they can from published walkthroughs and StackOverflow answers, but they end up trying to use fields and filters for &lt;code&gt;rpc_completed&lt;/code&gt; from other events which don&amp;rsquo;t work. They also tend to hallucinate things like whether you can filter on a simple field for schema name on &lt;code&gt;rpc_completed&lt;/code&gt;. (You can&amp;rsquo;t.)&lt;/p&gt;
&lt;p&gt;Possibly this post will make them a bit better by giving them more examples to scrape and work with. Good luck, robots.&lt;/p&gt;
&lt;h2 id="sp_humanevents-can-save-time"&gt;sp_HumanEvents Can Save Time&lt;/h2&gt;
&lt;p&gt;If you want a simpler way to create Extended Events sessions with sensible defaults and filtering, check out &lt;a href="https://github.com/erikdarlingdata/DarlingData/tree/main/sp_HumanEvents"&gt;Erik Darling&amp;rsquo;s sp_HumanEvents&lt;/a&gt;, a stored procedure that creates Extended Events sessions for common troubleshooting scenarios.&lt;/p&gt;
&lt;h2 id="why-rpc_completed-events-are-useful-for-troubleshooting"&gt;Why RPC_Completed Events Are Useful for Troubleshooting&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;rpc_completed&lt;/code&gt; event has a key advantage over &lt;code&gt;sql_batch_completed&lt;/code&gt;: it always captures parameter values for stored procedures and parameterized queries.&lt;/p&gt;
&lt;p&gt;This makes it more useful when you want to set up code to reproduce a problem. It also makes it useful for troubleshooting parameter sniffing problems, where you need to see which specific parameter values are being passed in to run queries, as this isn&amp;rsquo;t captured in Query Store.&lt;/p&gt;
&lt;h2 id="data-fields-in-the-rpc_completed-event-and-how-to-query-them"&gt;Data Fields in the RPC_Completed Event (and How to Query Them)&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;rpc_completed&lt;/code&gt; event captures several useful data fields automatically as part of the event payload.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Beware&lt;/strong&gt;: There are docs pages for &lt;strong&gt;Profiler&lt;/strong&gt; events, like this one for &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/event-classes/rpc-completed-event-class" &gt;RPC:Completed Event Class&lt;/a&gt;, but the column list and their names for Profiler Event Classes are different than what you get in Extended Events. Using this documentation to write XEvents scripts is a gotcha that will waste time.
&lt;/div&gt;
&lt;p&gt;You can query the available fields for an event with TSQL and the event name, which is handy because there isn&amp;rsquo;t a docs page for the properties of each Extended Event. Or maybe it&amp;rsquo;s &lt;strong&gt;why&lt;/strong&gt; there isn&amp;rsquo;t a docs page? The software is supposed to be self-documenting, I guess.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_type&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_object_columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rpc_completed&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Useful data fields for &lt;code&gt;rpc_completed&lt;/code&gt; include the following, along with their descriptions from SQL Server 2025. Earlier versions may return different time increments, SQL Server used milliseconds in its early versions of XEvents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;statement&lt;/code&gt;: The text of the statement that was run by the remote procedure call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cpu_time&lt;/code&gt;: The CPU time (in microseconds) used by the remote procedure call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;duration&lt;/code&gt;: The time (in microseconds) that the remote procedure call took to be completed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;logical_reads&lt;/code&gt;: The number of logical page reads that were issued by the remote procedure call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;physical_reads&lt;/code&gt;: The number of physical page reads that were issued by the remote procedure call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;writes&lt;/code&gt;: The number of page writes that were issued by the remote procedure call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;row_count&lt;/code&gt;: The number of rows that were returned by the remote procedure call.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;result&lt;/code&gt;: The return value from the remote procedure call.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These fields are automatically captured. &lt;code&gt;Logical_reads&lt;/code&gt;, &lt;code&gt;physical_reads&lt;/code&gt;, and &lt;code&gt;writes&lt;/code&gt; are returned in the count of 8KB pages, so multiply by 8, then divide by 1024. if you want to translate into MB read. &lt;code&gt;Physical_reads&lt;/code&gt; is always a subset of &lt;code&gt;logical_reads&lt;/code&gt;, because pages need to be pulled into memory to be read.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;event_time&lt;/code&gt; is also automatically available. This will always be in the &lt;strong&gt;UTC time zone&lt;/strong&gt;, even if you have the timezone for the SQL Server Instance set to something else. I always say that East Coast time is best coast time, but I guess someone got tired of dealing with Daylight Savings Time, and who can blame them.&lt;/p&gt;
&lt;h2 id="how-to-query-available-actions"&gt;How to Query Available Actions&lt;/h2&gt;
&lt;p&gt;To get additional context like the database name or client application name, add those as &lt;code&gt;actions&lt;/code&gt; in the EVENT definition.&lt;/p&gt;
&lt;p&gt;This query returns actions. There&amp;rsquo;s no way I&amp;rsquo;ve found to query the actions that will return meaningful data for a specific Extended Event, it&amp;rsquo;s a game of trial and error.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capabilities_desc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_packages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;package_guid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;action&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I see 83 actions on SQL Server 2025. Popular actions with their description are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sqlserver.client_app_name&lt;/code&gt;: Collect client application name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlserver.database_id&lt;/code&gt;: Collect database ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlserver.database_name&lt;/code&gt;: Collect current database name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlserver.username&lt;/code&gt;: Collect username&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following actions are often useful, but don&amp;rsquo;t return meaningful data for &lt;code&gt;rpc_completed&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sqlserver.query_hash&lt;/code&gt;: Collect query hash. Use this to identify queries with similar logic. You can use the query hash to determine the aggregate resource usage for queries that differ only by literal values&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlserver.query_plan_hash&lt;/code&gt;: Collect query plan hash. Use this to identify similar query execution plans. You can use query plan hash to find the cumulative cost of queries with similar execution plans&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For &lt;code&gt;RPC_Completed&lt;/code&gt;, the information we need is on the &lt;code&gt;statement&lt;/code&gt; data field, so I do not collect this action in the scripts below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sqlserver.sql_text&lt;/code&gt;: Collect SQL text&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are using Resource Governor, you can collect or filter by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sqlserver.session_resource_group_id&lt;/code&gt;: Collect current session resource group ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlserver.session_resource_pool_id&lt;/code&gt;: Collect current session resource pool ID&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-sends-rpc_completed-events"&gt;What Sends RPC_Completed Events&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rpc_completed&lt;/code&gt; events fire for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Stored procedure calls&lt;/strong&gt;: When an application or client executes a stored procedure (using the RPC protocol).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameterized queries&lt;/strong&gt;: When using &lt;code&gt;sp_executesql&lt;/code&gt; with parameters. You&amp;rsquo;ll take my dynamic SQL from my cold, dead hands. Also commonly used by .NET applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prepared statement execution&lt;/strong&gt;: When applications use prepared statements via &lt;code&gt;sp_prepare&lt;/code&gt;/&lt;code&gt;sp_execute&lt;/code&gt; (more common with ODBC and JDBC than .NET, which typically uses &lt;code&gt;sp_executesql&lt;/code&gt; for parameterized queries)&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Common error&lt;/strong&gt;: Queries you run from a SQL Server Management Studio session do &lt;strong&gt;not&lt;/strong&gt; fire &lt;code&gt;rpc_completed&lt;/code&gt; events. These are run as T-SQL batches, even if you run a stored procedure in the T-SQL batch.&lt;BR /&gt;
&lt;BR /&gt;
For this reason, we'll use PowerShell to test firing RPC events in the code below.
&lt;/div&gt;
&lt;h2 id="create-an-extended-events-session-for-rpc_completed-with-minimal-filters"&gt;Create an Extended Events Session for RPC_Completed with Minimal Filters&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create a basic Extended Events session to capture all RPC calls.&lt;/p&gt;
&lt;p&gt;Even in this simple example, I&amp;rsquo;m filtering out system database and system session calls as a sensible default. (If you need those, you can delete that whole WHERE clause.)&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_rpc_calls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rpc_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;greater_than_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude master, model, msdb, tempdb */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_boolean&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;is_system&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude system sessions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\capture_rpc_calls.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_rpc_calls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="create-a-stored-procedure-to-test"&gt;Create a Stored Procedure to Test&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s also create a stored procedure in SSMS. I&amp;rsquo;m using the StackOverflow2013 sample database.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Create a simple test procedure */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;StartDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;StartDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="generate-rpc_completed-extended-events-with-a-powershell-script"&gt;Generate RPC_Completed Extended Events with a PowerShell Script&lt;/h2&gt;
&lt;p&gt;With those in place, let&amp;rsquo;s generate some &lt;code&gt;rpc_completed&lt;/code&gt; events, and also run a query that should not generate an &lt;code&gt;rpc_completed&lt;/code&gt; event.&lt;/p&gt;
&lt;p&gt;Save this PowerShell script as &lt;code&gt;Test-RpcCompletedEvents.ps1&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Test script to generate RPC completed events for Extended Events testing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nv"&gt;$ServerInstance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;localhost\FABRIC&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nv"&gt;$Database&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;StackOverflow2013&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Connecting to &lt;/span&gt;&lt;span class="nv"&gt;$ServerInstance&lt;/span&gt;&lt;span class="s2"&gt;, database &lt;/span&gt;&lt;span class="nv"&gt;$Database&lt;/span&gt;&lt;span class="s2"&gt;...&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Cyan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;New-Object&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;SqlClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;SqlConnection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ConnectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Server=&lt;/span&gt;&lt;span class="nv"&gt;$ServerInstance&lt;/span&gt;&lt;span class="s2"&gt;;Database=&lt;/span&gt;&lt;span class="nv"&gt;$Database&lt;/span&gt;&lt;span class="s2"&gt;;Integrated Security=True;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Connected successfully.&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;# This stored procedure call generates an rpc_completed event&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;1. Executing stored procedure (generates rpc_completed event)...&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Yellow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.Data.CommandType&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;StoredProcedure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;dbo.TestProc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AddWithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@UserId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;22656&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Out-Null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AddWithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@StartDate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2013-01-01&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Out-Null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; Stored procedure executed.&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;# This also generates an rpc_completed event (sp_executesql)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;2. Executing parameterized query (generates rpc_completed event via sp_executesql)...&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Yellow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.Data.CommandType&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SELECT PostCount = COUNT(*) FROM dbo.Posts AS p WHERE p.OwnerUserId = @UserId AND p.CreationDate &amp;gt;= @StartDate&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AddWithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@UserId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;22656&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Out-Null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AddWithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@StartDate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2013-01-01&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Out-Null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; Parameterized query executed.&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;# This does NOT generate an rpc_completed event (T-SQL batch, not RPC)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;3. Executing T-SQL batch (does NOT generate rpc_completed event)...&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Yellow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command3&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.Data.CommandType&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SELECT YouDoNotSeeMeInYourTrace = COUNT(*) FROM dbo.Posts AS p WHERE p.OwnerUserId = 22656 AND p.CreationDate &amp;gt;= &amp;#39;2013-01-01&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; T-SQL batch executed.&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;# Additional test: sp_executesql with Users table (for the dynamic SQL filter example)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;4. Executing parameterized query against Users table (for dynamic SQL filter testing)...&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Yellow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command4&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CreateCommand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.Data.CommandType&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SELECT u.Id, u.DisplayName, u.Reputation FROM dbo.Users AS u WHERE u.Location = @Location&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AddWithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@Location&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;New York, NY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Out-Null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$command4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ExecuteNonQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; Users query executed.&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;All test queries completed!&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Cyan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Note: Extended Events may take up to 30 seconds to flush events to file (MAX_DISPATCH_LATENCY).&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Yellow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Error: &lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Red&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;State&lt;/span&gt; &lt;span class="o"&gt;-eq&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;`n&lt;/span&gt;&lt;span class="s2"&gt;Connection closed.&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ForegroundColor&lt;/span&gt; &lt;span class="n"&gt;Cyan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The script executes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A stored procedure call (generates &lt;code&gt;rpc_completed&lt;/code&gt; event)&lt;/li&gt;
&lt;li&gt;A parameterized query via &lt;code&gt;sp_executesql&lt;/code&gt; (generates &lt;code&gt;rpc_completed&lt;/code&gt; event)&lt;/li&gt;
&lt;li&gt;A T-SQL batch without parameters (does NOT generate &lt;code&gt;rpc_completed&lt;/code&gt; event)&lt;/li&gt;
&lt;li&gt;An additional parameterized query against the Users table (for testing dynamic SQL filters)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run it with:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# With default values (localhost\FABRIC and StackOverflow2013):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Test-RpcCompletedEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Or specify your server and database:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Test-RpcCompletedEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="n"&gt;-ServerInstance&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;YourServer\YourInstance&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-Database&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;YourDatabase&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="query-the-xevents-trace-file-and-parse-the-xml"&gt;Query the XEvents Trace File and Parse the XML&lt;/h2&gt;
&lt;p&gt;Read from the trace file to verify what was captured. We set &lt;code&gt;MAX_DISPATCH_LATENCY&lt;/code&gt; to 30 seconds in our XEvents trace definition (which is also the default), so it may take up that amount of time for data to be flushed to the file. (&lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/create-event-session-transact-sql#max_dispatch_latency---seconds-seconds--infinite-"&gt;Docs on CREATE EVENT SESSION&lt;/a&gt;)&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Read and parse the events from the file */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/@timestamp)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;database_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/action[@name=&amp;#34;username&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;object_name&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(128)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;statement&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nvarchar(max)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;duration&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu_time_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;cpu_time&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;logical_reads&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;row_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(event/data[@name=&amp;#34;row_count&amp;#34;]/value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bigint&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;full_event_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_xe_file_target_read_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\capture_rpc_calls*.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xe&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The results show:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stored procedure executions were captured, including sp_executesql calls (RPC calls)&lt;/li&gt;
&lt;li&gt;The ad-hoc SELECT was not (language event)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/rpc_events_captured.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The statements for calls to sp_executesql were captured with the parameter values. For example:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SELECT PostCount = COUNT(*) FROM dbo.Posts AS p WHERE p.OwnerUserId = @UserId AND p.CreationDate &amp;gt;= @StartDate&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@UserId int,@StartDate nvarchar(10)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;22656&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;StartDate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2013-01-01&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="filter-rpc_completed-by-object-name"&gt;Filter RPC_Completed by Object Name&lt;/h2&gt;
&lt;p&gt;You usually don&amp;rsquo;t want to capture every RPC call. Filtering to just capture what you need makes the trace lighter, and also your life easier going through the trace when problem solving.&lt;/p&gt;
&lt;p&gt;Filtering by object name and by the login executing the commands is very useful:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_specific_proc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rpc_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TestProc&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;greater_than_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude master, model, msdb, tempdb */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_boolean&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;is_system&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude system sessions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by SQL login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;SQLLoginName&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by Windows login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;DOMAIN\WindowsUser&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\capture_specific_proc.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_specific_proc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;object_name&lt;/code&gt; predicate matches the procedure name, but without the schema.&lt;/p&gt;
&lt;p&gt;The example above uses an equality. To pattern match with a case-insensitive comparison, use the &lt;code&gt;like_i_sql_unicode_string&lt;/code&gt; predicate operator instead:&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;like_i_sql_unicode_string&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Rerunning &lt;code&gt;Test-RpcCompletedEvents.ps1&lt;/code&gt; and then the query to read from the file (adapted for this trace file name), this captured only the call to &lt;code&gt;TestProc&lt;/code&gt;:&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/rpc_events_captured_filter_objectname.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="filter-rpc_completed-by-object-name-and-sql-text"&gt;Filter RPC_Completed by Object Name and SQL Text&lt;/h2&gt;
&lt;p&gt;You can combine &lt;code&gt;object_name&lt;/code&gt; and &lt;code&gt;statement&lt;/code&gt; filters for more precise targeting. This is useful when you want to ensure you&amp;rsquo;re capturing a specific procedure and also verify it&amp;rsquo;s being called in a particular way.&lt;/p&gt;
&lt;p&gt;This is also useful because there is &lt;strong&gt;not&lt;/strong&gt; a &lt;code&gt;schema_name&lt;/code&gt; field to filter on.&lt;/p&gt;
&lt;p&gt;The following example only works if the exact statement being issued leads with &lt;code&gt;exec dbo.TestProc&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_testproc_with_sqltext&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rpc_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TestProc&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;like_i_sql_unicode_string&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;exec dbo.TestProc%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;greater_than_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude master, model, msdb, tempdb */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_boolean&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;is_system&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude system sessions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by SQL login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;SQLLoginName&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by Windows login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;DOMAIN\WindowsUser&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\capture_testproc_with_sqltext.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_testproc_with_sqltext&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I tested this to make sure it works, but the output is the same as above: it captures dbo.TestProc.&lt;/p&gt;
&lt;h2 id="filter-rpc_completed-for-a-specific-query-called-by-sp_executesql"&gt;Filter RPC_Completed for a Specific Query Called by sp_executesql&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s common for applications to use &lt;code&gt;sp_executesql&lt;/code&gt; to execute parameterized queries against SQL Server.&lt;/p&gt;
&lt;p&gt;In this case, the &lt;code&gt;object_name&lt;/code&gt; will be &lt;code&gt;sp_executesql&lt;/code&gt;. To filter for specific dynamic SQL, you need to filter on the &lt;code&gt;statement&lt;/code&gt; data field, which contains the actual SQL statement being executed.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_specific_dynamic_sql&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rpc_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sp_executesql&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;like_i_sql_unicode_string&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%FROM dbo.Users%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;greater_than_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude master, model, msdb, tempdb */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_boolean&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;is_system&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude system sessions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by SQL login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;SQLLoginName&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by Windows login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;DOMAIN\WindowsUser&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\capture_specific_dynamic_sql.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_specific_dynamic_sql&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a match!&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/rpc_events_captured_filter_sp-executesql.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="filter-rpc_completed-by-duration-or-logical-reads"&gt;Filter RPC_Completed by Duration or Logical Reads&lt;/h2&gt;
&lt;p&gt;You may want to only capture queries of a certain duration or that do more than a given amount of IO.&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_by_duration_reads&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rpc_completed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StackOverflow2013&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TestProc&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UpdateUserReputation&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;GetTopUsers&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* More than 5 seconds (in microseconds) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* More than 10,000 logical reads */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;greater_than_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude master, model, msdb, tempdb */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_boolean&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;is_system&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Exclude system sessions */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by SQL login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;SQLLoginName&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Uncomment to filter by Windows login */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* AND [sqlserver].[username] = N&amp;#39;DOMAIN\WindowsUser&amp;#39; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\Temp\capture_by_duration_reads.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_rollover_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;capture_by_duration_reads&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This session will only capture calls that meet your thresholds. One event matches the criteria:&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/rpc_events_captured_filter_above_reads_threshold_and_name_match.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="extended-events-session-cleanup-script"&gt;Extended Events Session Cleanup Script&lt;/h2&gt;
&lt;p&gt;This stops and drops all Extended Events sessions created in this post (and any others that begin with &amp;lsquo;capture&amp;rsquo;)&lt;/p&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Stop and drop all sessions named like capture% */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;session_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_cursor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURSOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LOCAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FAST_FORWARD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;capture%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_cursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_cursor&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;session_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;FETCH_STATUS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Stop the session if it&amp;#39;s running */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;stop_sql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; ALTER EVENT SESSION &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;session_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; ON SERVER
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; STATE = STOP;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;stop_sql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CATCH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Session might not be running, continue */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CATCH&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Drop the session */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;drop_sql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; DROP EVENT SESSION &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;session_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; ON SERVER;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;drop_sql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_cursor&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;session_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CLOSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_cursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DEALLOCATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_cursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Verify all sessions are removed */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server_event_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;capture%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id="rpc_completed-filtering-strategies"&gt;Rpc_completed Filtering Strategies&lt;/h2&gt;
&lt;p&gt;When filtering &lt;code&gt;rpc_completed&lt;/code&gt; events&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start specific&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filtering by the &lt;code&gt;[sqlserver].[username]&lt;/code&gt; running the query is usually a good thing&lt;/li&gt;
&lt;li&gt;Filter by &lt;code&gt;object_name&lt;/code&gt; if troubleshooting a known procedure
&lt;ul&gt;
&lt;li&gt;Equality example: &lt;code&gt;[object_name] = N'TestProc'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Like example: &lt;code&gt;[sqlserver].[like_i_sql_unicode_string]([object_name], N'test%')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For parameterized queries sent from applications (like Entity Framework), the &lt;code&gt;object_name&lt;/code&gt; will usually be &lt;code&gt;sp_executesql&lt;/code&gt;, so filter by &lt;code&gt;[object_name] = N'sp_executesql'&lt;/code&gt; and add filters on the &lt;code&gt;statement&lt;/code&gt; field to narrow down to specific queries&lt;/li&gt;
&lt;li&gt;Filter on &lt;code&gt;database_name&lt;/code&gt; to avoid capturing the same procedure name in different databases
&lt;ul&gt;
&lt;li&gt;Equality example: &lt;code&gt;[sqlserver].[database_name] = N'StackOverflow2013'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Otherwise at least filter out system databases if you can with &lt;code&gt;[package0].[greater_than_uint64]([sqlserver].[database_id], (4))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Filter out system activity with &lt;code&gt;[package0].[equal_boolean]([sqlserver].[is_system], (0))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You can filter on schema name, but only in the statement&lt;/strong&gt;: There is no schema name field to filter on for &lt;code&gt;rpc_completed&lt;/code&gt; events. If you need to filter by schema, you can filter on the &lt;code&gt;statement&lt;/code&gt; field using &lt;code&gt;[sqlserver].[like_i_sql_unicode_string]([statement], N'exec dbo.TestProc%')&lt;/code&gt; to match schema-qualified procedure calls. This approach depends on how the application calls the procedure, so you&amp;rsquo;ll need to take samples first to narrow this down.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Combine object and performance filters&lt;/strong&gt;: Filter by object name AND duration to catch only the slow executions for RPC events. You can also filter by logical_reads to exclude calls that do a minimum of IO. For parameterized queries from applications, combine &lt;code&gt;[object_name] = N'sp_executesql'&lt;/code&gt; with performance filters like &lt;code&gt;[duration] &amp;gt; 5000000&lt;/code&gt; to capture expensive parameterized queries without capturing every single execution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test filters in development first&lt;/strong&gt;: Create the session in a dev environment to verify your filters capture what you expect before deploying to production. Remember that queries run from SSMS do not fire &lt;code&gt;rpc_completed&lt;/code&gt; events (they&amp;rsquo;re T-SQL batches, not RPC calls), so use the PowerShell script or an application connection to test your filters.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sample by session_id for high-volume scenarios&lt;/strong&gt;: You can sample a percentage of sessions using the &lt;code&gt;divides_by_uint64&lt;/code&gt; function on &lt;code&gt;session_id&lt;/code&gt;. The example sampling traces in the XEvents tooling suggest this technique:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="code-block-wrapper" data-collapsible="true" data-start-collapsed="true"&gt;&lt;div class="highlight"&gt;&lt;pre class="chroma" data-collapsible="true" data-start-collapsed="true"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;divides_by_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Sample 20% of sessions (every 5th session) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Adjust the divisor in &lt;code&gt;divides_by_uint64&lt;/code&gt; to change the sampling rate: use &lt;code&gt;10&lt;/code&gt; for 10% sampling, &lt;code&gt;20&lt;/code&gt; for 5% sampling, etc.&lt;/p&gt;
&lt;h2 id="capture-the-signal-not-the-noise"&gt;Capture the Signal, Not the Noise&lt;/h2&gt;
&lt;p&gt;Without filtering, XEvents traces often generate an overwhelming amount of data.&lt;/p&gt;
&lt;p&gt;The filtering techniques in this post (object name, SQL text matching, performance thresholds, and session sampling) focus on the events that matter. Filtering by specific procedures, expensive queries, or a sample of sessions captures the signal needed for troubleshooting without extraneous noise.&lt;/p&gt;</description></item><item><title>Erik Darling and Kendra Little Talk AI, Databases, and SQL Server 2025</title><link>https://kendralittle.com/2025/12/09/erik-darling-kendra-little-talk-ai-databases-sql-server-2025-dear-sql-dba/</link><pubDate>Tue, 09 Dec 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/12/09/erik-darling-kendra-little-talk-ai-databases-sql-server-2025-dear-sql-dba/</guid><description>&lt;p&gt;&lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt; joins me &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;on the Dear SQL DBA Podcast&lt;/a&gt; to chat about AI tools, why they work better for Python and PowerShell than SQL, and what&amp;rsquo;s exciting (and what&amp;rsquo;s not) in SQL Server 2025.&lt;/p&gt;
&lt;p&gt;Along the way we describe the ONE THING we always want to configure in Resource Governor, why at least one SQL Server 2025 feature should be backported to 2022, and whether the universe is text files all the way down.&lt;/p&gt;
&lt;h2 id="audio-only"&gt;Audio only&lt;/h2&gt;
&lt;iframe title="Embed Player" style="border:none" src="https://play.libsyn.com/embed/episode/id/39328610/height/64/theme/modern/size/small/thumbnail/no/custom-color/467fbf/time-start/00:00:00/playlist-height/200/direction/backward/hide-subscribe/yes/hide-share/yes/font-color/FFFFFF" height="64" width="100%" scrolling="no" allowfullscreen="" webkitallowfullscreen="true" mozallowfullscreen="true" oallowfullscreen="true" msallowfullscreen="true"&gt;&lt;/iframe&gt;
&lt;h2 id="video"&gt;Video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/2f44iNywOAI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="in-this-conversation"&gt;In this Conversation&lt;/h2&gt;
&lt;p&gt;Erik and I talked about how we currently use AI tools, plus topics related to SQL Server 2025 in this episode.&lt;/p&gt;
&lt;p&gt;Erik&amp;rsquo;s approach to AI is to treat it like a junior developer rather than a SQL Server expert. He uses AI primarily to automate tasks. AI helps him working with APIs to help him reduce manual work to run his business.&lt;/p&gt;
&lt;p&gt;We discussed why AI produces better code for Python and PowerShell than SQL. Scripting languages have less ambiguity and clearer error messages, while SQL requires deep context about indexes, data distribution, and performance that AI struggles with.&lt;/p&gt;
&lt;p&gt;The highlights we discussed with SQL Server 2025 are Query Store on readable secondaries (finally), Resource Governor now available in Standard Edition, and Standard Edition supporting up to 256GB of memory. The AI features are limited, with DISKANN indexes (vector indexes) making tables read-only. We discussed being wary of enabling preview features with a database scoped level flag: seems fine for development, but this could have unwelcome surprises if you do this in production.&lt;/p&gt;
&lt;h2 id="where-to-jump-in"&gt;Where to Jump In&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where the major topics start in the conversation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;[0:00]&lt;/strong&gt; Introduction and opening banter about AI tools in interviews&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[2:42]&lt;/strong&gt; Erik&amp;rsquo;s approach to using AI tools and agents for productivity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[11:06]&lt;/strong&gt; Why AI works better for Python and PowerShell than SQL&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[19:45]&lt;/strong&gt; SQL Server 2025: Finally, Query Store on readable secondaries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[27:20]&lt;/strong&gt; Standard Edition improvements: Resource Governor and memory limits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[31:50]&lt;/strong&gt; AI features in SQL Server 2025 and preview features concerns&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="more-dear-sql-dba"&gt;More Dear SQL DBA&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;episode index&lt;/a&gt; for more conversations about database problems, performance tuning, and the real challenges database professionals face.&lt;/p&gt;</description></item><item><title>Azure SQL Managed Instance Memory-to-Core Math Still Doesn't Work, Even in GPv2</title><link>https://kendralittle.com/2025/12/08/azure-sql-managed-instance-memory-to-core-math-still-doesnt-work-even-in-gpv2/</link><pubDate>Mon, 08 Dec 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/12/08/azure-sql-managed-instance-memory-to-core-math-still-doesnt-work-even-in-gpv2/</guid><description>&lt;p&gt;Microsoft recently announced that &lt;a href="https://techcommunity.microsoft.com/blog/azuresqlblog/generally-available-azure-sql-managed-instance-next-gen-general-purpose/4470970"&gt;Azure SQL Managed Instance Next-gen General Purpose (GPv2) is generally available&lt;/a&gt;. GPv2 brings significant storage performance improvements over GPv1. If you&amp;rsquo;re using GPv1, you should plan to upgrade.&lt;/p&gt;
&lt;p&gt;But GPv2 still has the same memory-to-core ratio problem that makes Managed Instance a rough deal for running SQL Server. SQL Server is engineered to use lots of memory—it&amp;rsquo;s a rare OLTP or mixed-OLTP workload that doesn&amp;rsquo;t need significant cache for reliable performance. We&amp;rsquo;ll have a look at the pricing math.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/DatabaseSardines.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="whats-new-in-gpv2"&gt;What&amp;rsquo;s New in GPv2&lt;/h2&gt;
&lt;p&gt;GPv2 entered public preview in &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;March 2024&lt;/a&gt; and remained there for 20 months before reaching general availability. The new tier brings significant improvements over GPv1. According to the announcement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Better I/O latency&lt;/strong&gt;: Average latency drops from 5-10ms to 3-4ms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Higher IOPS&lt;/strong&gt;: Maximum data IOPS increases from 30-50k to 80k&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More storage&lt;/strong&gt;: Maximum storage increases from 16TB to 32TB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More databases per instance&lt;/strong&gt;: Up to 500 databases per instance (up from 100)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More vCores&lt;/strong&gt;: Maximum vCores increases from 80 to 128&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory slider&lt;/strong&gt;: New flexible memory configuration options&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster scaling&lt;/strong&gt;: Storage and IOPS can be resized independently of compute&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note on Memory Slider&lt;/strong&gt;: The maximum amount of memory per vCore has not increased. Azure SQL Managed Instance still maxes out at 13.6 GB per vCore for memory-optimized hardware.
&lt;/div&gt;
&lt;h2 id="why-gpv1-is-a-problem"&gt;Why GPv1 is a Problem&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve been using Azure SQL Managed Instance General Purpose, you&amp;rsquo;ve likely experienced storage pains with GPv1. I&amp;rsquo;ve written about &lt;a href="https://kendralittle.com/2024/12/18/azure-sql-managed-instance-storage-regularly-slow-60-seconds/"&gt;how Azure SQL Managed Instance storage regularly stalls for 15-60 seconds in GPv1&lt;/a&gt;, despite Microsoft&amp;rsquo;s documentation claiming &amp;ldquo;5-10 ms&amp;rdquo; latency.&lt;/p&gt;
&lt;p&gt;These storage stalls cause real problems. SQL Server treats I/O requests that take longer than 15 seconds as serious errors because these stalls cause blocking, query timeouts, and cascading performance issues that last far longer than the initial stall.&lt;/p&gt;
&lt;p&gt;GPv1 uses &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla#general-purpose-service-tier"&gt;Azure Blob Storage&lt;/a&gt; for database files, which has fundamental limitations, including &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits#file-io-characteristics-in-general-purpose-tier"&gt;file size-based IOPS throttling&lt;/a&gt; that causes customers to have to grow files unnecessarily and makes performance management difficult and unpredictable. GPv2 uses &lt;a href="https://techcommunity.microsoft.com/blog/azuresqlblog/generally-available-azure-sql-managed-instance-next-gen-general-purpose/4470970"&gt;Azure Elastic SAN for storage&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-features-exiting-preview-matters"&gt;Why Features Exiting Preview Matters&lt;/h2&gt;
&lt;p&gt;Preview features come with important caveats.&lt;/p&gt;
&lt;p&gt;Now that GPv2 is generally available, it&amp;rsquo;s backed by Microsoft&amp;rsquo;s standard SLAs. If there are outages or problems, you&amp;rsquo;re entitled to service credits. The feature is committed to long-term support, and Microsoft can&amp;rsquo;t just remove it overnight.&lt;/p&gt;
&lt;h2 id="all-managed-instance-customers-should-consider-gpv2"&gt;All Managed Instance Customers Should Consider GPv2&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re running Azure SQL Managed Instance GPv1, plan your upgrade to GPv2. The performance improvements are significant, and the storage architecture is fundamentally better.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth your time to plan this proactively. The &lt;a href="https://techcommunity.microsoft.com/blog/azuresqlblog/november-2022-feature-wave-for-azure-sql-managed-instance/3677741"&gt;November 2022 feature wave&lt;/a&gt; was announced in November 2022 and I&amp;rsquo;m pretty sure it didn&amp;rsquo;t finish rolling out until sometime in 2024. If you aren&amp;rsquo;t proactive about upgrades, you could be waiting a while based on that past history.&lt;/p&gt;
&lt;p&gt;Microsoft notes that zonal redundancy isn&amp;rsquo;t included in the initial GA release but is being worked on.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Azure SQL Managed Instance Business Critical, consider if General Purpose might meet your needs with GPv2. You may have to overprovision vCores to get the memory you need for your workload, but the pricing difference might still make sense if the performance works. See the &lt;a href="#microsoft-still-needs-to-provide-more-for-managed-instance-customers"&gt;pricing comparisons below&lt;/a&gt; to note the differences between Business Critical and General Purpose pricing.&lt;/p&gt;
&lt;h2 id="you-should-still-monitor-for-storage-latency-issues"&gt;You Should Still Monitor for Storage Latency Issues&lt;/h2&gt;
&lt;p&gt;Even though GPv2 uses better storage technology, you should still monitor your SQL Server error logs for storage latency errors. The underlying causes may be different from GPv1&amp;rsquo;s problems, but storage latency issues can still occur for various reasons: network problems, Azure infrastructure issues, or other factors.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve written about &lt;a href="https://kendralittle.com/2024/12/18/azure-sql-managed-instance-storage-regularly-slow-60-seconds/"&gt;how to find these errors in the SQL Server log&lt;/a&gt;. Look for messages containing &amp;ldquo;longer than 15 seconds&amp;rdquo; in your error log. Use &lt;a href="https://erikdarling.com/sp_loghunter/"&gt;Erik Darling&amp;rsquo;s free sp_loghunter utility&lt;/a&gt; to search the logs programmatically.&lt;/p&gt;
&lt;p&gt;On GPv1, these storage latency problems went largely unresolved and undiscussed for many years. Don&amp;rsquo;t let that happen again. If you see storage latency issues on GPv2, document them and report them to Microsoft support.&lt;/p&gt;
&lt;h2 id="microsoft-still-needs-to-provide-more-for-managed-instance-customers"&gt;Microsoft Still Needs to Provide More for Managed Instance Customers&lt;/h2&gt;
&lt;p&gt;While GPv2 is a welcome improvement, Microsoft still has work to do to compete effectively with other cloud database offerings. I&amp;rsquo;ve written about &lt;a href="https://kendralittle.com/2025/10/08/three-differentiators-rds-sql-server-managed-database-cloud/"&gt;three reasons RDS SQL Server is better than Azure SQL Managed Instance&lt;/a&gt;, and the memory-to-core ratio issue is particularly important.&lt;/p&gt;
&lt;p&gt;SQL Server OLTP workloads benefit enormously from having large amounts of memory to reduce physical I/O. Memory access is always dramatically faster than storage access, and SQL Server is engineered to maximize use of the buffer pool and other caches.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s more critical than ever that Microsoft improves their memory-to-core ratios to provide a platform suitable for cache-hungry SQL Server. The comparison is stark between SQL Server 2025 prices for Standard Edition and pricing for Managed Instance General Purpose.&lt;/p&gt;
&lt;h3 id="sql-server-2025-pricing"&gt;SQL Server 2025 Pricing&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Cores&lt;/th&gt;
&lt;th&gt;Total Memory&lt;/th&gt;
&lt;th&gt;Memory per Core&lt;/th&gt;
&lt;th&gt;Cost per Month&lt;/th&gt;
&lt;th&gt;Cost per Year&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server 2025 Standard (one-time license)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;256 GB (max for Standard)&lt;/td&gt;
&lt;td&gt;64 GB&lt;/td&gt;
&lt;td&gt;$657.50&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$7,890&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server 2025 Enterprise (one-time license)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;256 GB (can go much higher without increasing licensing cost)&lt;/td&gt;
&lt;td&gt;64 GB&lt;/td&gt;
&lt;td&gt;$2,520.50&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$30,246&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Pricing source: &lt;a href="https://cdn-dynmedia-1.microsoft.com/is/content/microsoftcorp/microsoft/bade/documents/products-and-services/en-us/cloud/SQL-Server-2025-Pricing.pdf"&gt;SQL Server 2025 pricing&lt;/a&gt;, assumes 4 cores (2-core packs × 2)&lt;/li&gt;
&lt;li&gt;Price doesn&amp;rsquo;t include hardware, staff to manage Availability Groups, or Software Assurance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What would I need to pay to get the same amount of memory on Azure SQL Managed Instance? I&amp;rsquo;m just estimating 256 GB of memory here, not a ton for a production database. But &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits"&gt;13.6 GB of memory per core&lt;/a&gt; is still the maximum available in either General Purpose or Business Critical (you must choose Memory Optimized premium-series hardware to get it).&lt;/p&gt;
&lt;h3 id="managed-instance-pricing-to-get-the-same-amount-of-memory"&gt;Managed Instance Pricing to Get the Same Amount of Memory&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;d have to pay for &lt;strong&gt;19 vCores&lt;/strong&gt; to get 256GB or memory on Managed Instance. 19 vCores isn&amp;rsquo;t an option, so you&amp;rsquo;ll need to pay for &lt;strong&gt;20&lt;/strong&gt; vCores. Here&amp;rsquo;s what the Azure Pricing calculator says for East US as of November 30, 2025:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Cores&lt;/th&gt;
&lt;th&gt;Total Memory&lt;/th&gt;
&lt;th&gt;Memory per Core&lt;/th&gt;
&lt;th&gt;Cost per Month&lt;/th&gt;
&lt;th&gt;Cost per Year&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Managed Instance GPv2 (Next Generation General Purpose)&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;272 GB&lt;/td&gt;
&lt;td&gt;13.6 GB&lt;/td&gt;
&lt;td&gt;$5,051.10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$60,613.20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed Instance Business Critical&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;272 GB&lt;/td&gt;
&lt;td&gt;13.6 GB&lt;/td&gt;
&lt;td&gt;$12,672.80&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$152,073.60&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These prices vary by region. In Central US your budget needs to be bigger:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Cores&lt;/th&gt;
&lt;th&gt;Total Memory&lt;/th&gt;
&lt;th&gt;Memory per Core&lt;/th&gt;
&lt;th&gt;Cost per Month&lt;/th&gt;
&lt;th&gt;Cost per Year&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Managed Instance GPv2 (Next Generation General Purpose)&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;272 GB&lt;/td&gt;
&lt;td&gt;13.6 GB&lt;/td&gt;
&lt;td&gt;$5,883.30&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$70,599.60&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed Instance Business Critical&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;272 GB&lt;/td&gt;
&lt;td&gt;13.6 GB&lt;/td&gt;
&lt;td&gt;$14,322.60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$171,871.20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Pricing source: &lt;a href="https://azure.microsoft.com/en-us/pricing/calculator/"&gt;Azure pricing calculator&lt;/a&gt;, Pay as You Go, US East region, 4 vCores Next Generation General Purpose, Premium-Series memory optimized (Hardware Type), 32GB storage minimum, no zone redundancy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These estimates only describe &lt;strong&gt;4 cores&lt;/strong&gt; for the one-time license workload&amp;ndash; if you&amp;rsquo;re reading this article you&amp;rsquo;ve got way more cores than that. Is the extra recurring cost worth not buying hardware (or using a VM in the cloud where you limit the active cores you have to license) or hiring someone to manage Availability Groups? ¯\_(ツ)_/¯&lt;/p&gt;
&lt;p&gt;In both cases, it&amp;rsquo;s possible to get better deals on pricing: either by buying from resellers or package deals in the case of on-prem, or by reserved instances and Azure credits deals in the case of cloud services.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Why am I so obsessed with memory?&lt;/strong&gt; SQL Server has been built to leverage caching for performance. The storage speeds in GPv2 and the local SSD options for Business Critical in Azure SQL ain't that great when it comes to modern storage speeds. If you need reliable database performance, sufficient memory to reduce the amount of physical I/O you do on these systems is table stakes.
&lt;BR/&gt;
&lt;BR/&gt;
I do believe there are very strong features in Azure SQL Managed Instance and that it can be a compelling product, but it badly needs more memory per vCore. This is a major flaw that undercuts the engineering achievements of the service.
&lt;/div&gt;
&lt;p&gt;Y&amp;rsquo;all, I don&amp;rsquo;t particularly enjoy managing Windows Clusters and Availability Groups, personally. I &lt;strong&gt;love&lt;/strong&gt; managed database services in the cloud. But Azure SQL Managed Instance needs to support memory configurations suitable to the product that it runs at a more reasonable price. Changes like that are what really makes SaaS database services take off.&lt;/p&gt;</description></item><item><title>Index Bloat in Postgres: Why It Matters, How to Identify, How to Resolve</title><link>https://kendralittle.com/2025/12/01/index-bloat-postgres-why-it-matters-how-to-identify-and-resolve/</link><pubDate>Mon, 01 Dec 2025 05:00:00 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/12/01/index-bloat-postgres-why-it-matters-how-to-identify-and-resolve/</guid><description>&lt;p&gt;Index bloat in Postgres can cause problems, but it&amp;rsquo;s easy to miss.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve written about &lt;a href="https://kendralittle.com/2025/06/26/why-wont-postgresql-use-covering-index/"&gt;how vacuum problems can prevent PostgreSQL from using covering indexes&lt;/a&gt;, and index bloat is one of the things that can make vacuum struggle.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what you need to know about index bloat, how to find it, and how to fix it.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Bloated.jpg"
alt="Illustration representing index bloat in PostgreSQL"&gt;
&lt;/figure&gt;
&lt;h2 id="what-is-index-bloat"&gt;What Is Index Bloat?&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Index bloat&amp;rdquo; describes an index that takes up significantly more space on disk than it actually needs. This occurs because Postgres stores indexes &lt;a href="https://www.postgresql.org/docs/current/storage-page-layout.html"&gt;in 8 KB fixed-size pages&lt;/a&gt; which can accumulate empty space over time.&lt;/p&gt;
&lt;p&gt;When you delete or update rows, the old index entries become &lt;a href="https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-SPACE-RECOVERY"&gt;&amp;ldquo;dead tuples&amp;rdquo;&lt;/a&gt;—they&amp;rsquo;re no longer valid, but they remain on the page taking up space. &lt;a href="https://www.postgresql.org/docs/current/sql-vacuum.html"&gt;Vacuum&lt;/a&gt; marks that space as available for reuse, but it doesn&amp;rsquo;t compact the pages themselves. You end up with pages that have a lot of empty space scattered throughout them.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;VAC FACT&lt;/strong&gt;: &lt;a href="https://www.postgresql.org/docs/current/sql-vacuum.html"&gt;VACUUM FULL&lt;/a&gt; can remove bloat, but it requires heavy locks and rewrites the whole table, so this isn't a workable option for databases unless there is a regular long downtime period and you don't mind the IO.
&lt;/div&gt;
&lt;h2 id="how-index-bloat-happens"&gt;How Index Bloat Happens&lt;/h2&gt;
&lt;p&gt;Index bloat accumulates through normal database operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deletes&lt;/strong&gt;: When you delete rows, the index entries pointing to those rows become dead tuples, but they stay in the index until vacuum runs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Updates&lt;/strong&gt;: Postgres implements updates as delete-plus-insert under &lt;a href="https://www.postgresql.org/docs/current/mvcc-intro.html"&gt;MVCC (Multi-Version Concurrency Control)&lt;/a&gt;. The old index entry becomes dead, and Postgres creates a new one&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Page splits&lt;/strong&gt;: When a B-tree index page becomes full, &lt;a href="https://www.postgresql.org/docs/16/btree-implementation.html#BTREE-STRUCTURE"&gt;PostgreSQL splits it into two pages&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low fillfactor&lt;/strong&gt;: You can reduce page splits by setting a lower &lt;a href="https://www.postgresql.org/docs/current/sql-createindex.html#INDEX-RELOPTION-FILLFACTOR"&gt;fillfactor&lt;/a&gt; when creating indexes, which leaves more free space on each page. B-tree indexes default to 90% fillfactor. Indexes with lower fillfactor leave more empty space. This isn&amp;rsquo;t the same thing as bloat (it&amp;rsquo;s on purpose), but going too low can have similar impacts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High update/delete activity&lt;/strong&gt;: Tables with frequent updates or deletes accumulate bloat faster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To reiterate what&amp;rsquo;s mentioned above (it&amp;rsquo;s a common misunderstanding): autovacuum removes dead tuples from tables and marks space in indexes as available for reuse, but it &lt;strong&gt;doesn&amp;rsquo;t&lt;/strong&gt; reclaim space in indexes.&lt;/p&gt;
&lt;h2 id="why-index-bloat-causes-problems"&gt;Why Index Bloat Causes Problems&lt;/h2&gt;
&lt;p&gt;When you have significant index bloat, vacuum has to work harder. Vacuum needs to scan indexes to find and remove references to dead tuples. If your indexes are bloated, they contain more pages because the pages aren&amp;rsquo;t compacted—an index that should be 10 GB might be 15 GB or more instead if bloat gets bad, and imagine how this expands for larger indexes. Vacuum has to scan through all the extra pages, which takes more time and consumes more CPU and IO resources. The more bloat, the more pages to scan, and the longer vacuum takes.&lt;/p&gt;
&lt;p&gt;In systems with heavy write workloads, this can create a vicious cycle: vacuum runs slowly because of bloat, which means it can&amp;rsquo;t keep up with new dead tuples, which creates more bloat, etc.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve seen cases where vacuum was taking hours on tables that should have been much quicker to vacuum, all because the indexes were severely bloated.&lt;/p&gt;
&lt;h2 id="how-to-identify-index-bloat"&gt;How to Identify Index Bloat&lt;/h2&gt;
&lt;p&gt;AWS provides a useful script for calculating index bloat percentage in RDS PostgreSQL instances: &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/postgresql-maintenance-rds-aurora/reindex.html"&gt;Rebuilding indexes&lt;/a&gt;. This script calculates &lt;code&gt;bloat_pct&lt;/code&gt; for each index and helps you identify which indexes need attention.&lt;/p&gt;
&lt;p&gt;The script compares the actual index size to the expected size based on the number of tuples, giving you a percentage of bloat. AWS recommends running &lt;code&gt;REINDEX&lt;/code&gt; when the bloat percentage is greater than 20%, but let your conscience be your guide.&lt;/p&gt;
&lt;h2 id="how-to-fix-index-bloat"&gt;How to Fix Index Bloat&lt;/h2&gt;
&lt;p&gt;Postgres supports online index rebuilds using &lt;code&gt;REINDEX CONCURRENTLY&lt;/code&gt;. Under concurrent mode, the index remains available for reads and writes during the rebuild operation. The &lt;a href="https://www.postgresql.org/docs/current/sql-reindex.html#SQL-REINDEX-CONCURRENTLY"&gt;PostgreSQL documentation&lt;/a&gt; explains that &lt;code&gt;REINDEX CONCURRENTLY&lt;/code&gt; builds a new index alongside the existing one, performs multiple passes to capture changes made during the rebuild, then switches constraints and names to point to the new index before dropping the old one. This process takes longer than a standard rebuild but allows normal operations to continue throughout.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the syntax:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;REINDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or for all indexes on a table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;REINDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;CONCURRENTLY&lt;/code&gt; keyword makes it online. Without it, &lt;code&gt;REINDEX&lt;/code&gt; takes an exclusive lock on the table, blocking all access.&lt;/p&gt;
&lt;h2 id="a-gotcha-failed-concurrent-rebuilds-leave-invalid-indexes"&gt;A Gotcha: Failed Concurrent Rebuilds Leave Invalid Indexes&lt;/h2&gt;
&lt;p&gt;If a &lt;code&gt;REINDEX CONCURRENTLY&lt;/code&gt; operation fails partway through, Postgres leaves behind an &amp;ldquo;invalid&amp;rdquo; index that you can&amp;rsquo;t use. According to the &lt;a href="https://www.postgresql.org/docs/current/sql-reindex.html"&gt;PostgreSQL documentation&lt;/a&gt;, when &lt;code&gt;REINDEX CONCURRENTLY&lt;/code&gt; fails, Postgres leaves behind a temporary index with a name ending in &lt;code&gt;_ccnew&lt;/code&gt;. This index won&amp;rsquo;t function for reads (but still has overhead for updates), so drop it before trying the rebuild again.&lt;/p&gt;
&lt;p&gt;You can find invalid indexes by looking for indexes whose name ends in &lt;code&gt;%_ccnew&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indexname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indexdef&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_indexes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Concurrent rebuilds create temporary indexes named like this */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indexname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%\_ccnew&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indexname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indexrelname&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_stat_user_indexes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or query the &lt;a href="https://www.postgresql.org/docs/current/catalog-pg-index.html"&gt;&lt;code&gt;pg_index&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.postgresql.org/docs/current/catalog-pg-class.html"&gt;&lt;code&gt;pg_class&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://www.postgresql.org/docs/current/catalog-pg-namespace.html"&gt;&lt;code&gt;pg_namespace&lt;/code&gt;&lt;/a&gt; system catalogs to find indexes marked as invalid:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_size&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexrelid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relnamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indisvalid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you find invalid indexes from a failed concurrent rebuild, drop them before trying again. You can use &lt;code&gt;DROP INDEX&lt;/code&gt; or &lt;code&gt;DROP INDEX CONCURRENTLY&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invalid_index_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;CONCURRENTLY&lt;/code&gt; keyword avoids blocking by not requiring an &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock on the table.&lt;/p&gt;
&lt;h2 id="sample-scripts-to-reproduce-index-bloat"&gt;Sample Scripts to Reproduce Index Bloat&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a script you can use on a test database to create and observe index bloat.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: This demo creates a small table that you probably wouldn't worry about in a production environment, but it'll give you an idea of how this works. The script requires the pgstattuple extension, and is not as comprehensive and efficient as the script linked to in the &lt;a href="#how-to-identify-index-bloat"&gt;How to Identify Index Bloat&lt;/a&gt; section above.
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EXTENSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pgstattuple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx_test_bloat_multi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Insert some sample data */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT_DATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;365&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Check index size and empty space on pages */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexrelname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indexname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Total size of the index on disk */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexrelid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Total number of pages: leaf pages + internal pages + empty pages + deleted pages */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leaf_pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;internal_pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty_pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleted_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Average density of leaf pages (0-100, lower = more empty space on pages) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_leaf_density&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_leaf_density&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Empty space on leaf pages based on current density */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* If density is 50%, then 50% of leaf page space is empty */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leaf_pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current_setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;block_size&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_leaf_density&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty_space&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Percentage of space on leaf pages that&amp;#39;s currently empty */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_leaf_density&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;empty_space_pct&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_stat_user_indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Use pgstatindex() to get actual page-level statistics from the index */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LATERAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pgstatindex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexrelname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test_bloat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the initial size and density - the primary key pages are 90.1% full, the multi column index pages are 70.1% full.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/postgres-table-bloat-before-deletes.png"
alt="Query results showing initial index size with high density and minimal empty space before any deletes"&gt;
&lt;/figure&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Delete a large portion of rows */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* You can recheck the size using the query above, but nothing will
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;be different until you run VACUUM. */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Run VACUUM ANALYZE */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VACUUM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ANALYZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Recheck the size using the query above */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now here&amp;rsquo;s our index size and empty space: the primary key pages are 45% full and the multi column index pages are 35.5% full.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/postgres-table-bloat-after-deletes-and-vacuum.png"
alt="Query results showing increased empty space and lower density after deleting rows and running VACUUM ANALYZE"&gt;
&lt;/figure&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Rebuild index concurrently to reclaim space */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;REINDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx_test_bloat_multi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;REINDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat_pkey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Recheck the size using the query above */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the size and empty space after rebuilds: each index is 90% full.&lt;/p&gt;
&lt;figure class="alignleft-block"&gt;&lt;img src="https://kendralittle.com/images/postgres-table-bloat-after-concurrent-rebuilds.png"
alt="Query results showing reduced index size and higher density after running REINDEX CONCURRENTLY to reclaim space"&gt;
&lt;/figure&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Clean up */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_bloat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="index-bloat-creeps-up-gradually"&gt;Index Bloat Creeps Up Gradually&lt;/h2&gt;
&lt;p&gt;Have you checked your indexes for bloat? Have you implemented automated maintenance for bloat?&lt;/p&gt;</description></item><item><title>How to See Rowcounts and Execution Time for In-Flight Queries in SQL Server</title><link>https://kendralittle.com/2025/11/24/how-to-see-rowcounts-execution-time-in-flight-queries-sql-server/</link><pubDate>Mon, 24 Nov 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/11/24/how-to-see-rowcounts-execution-time-in-flight-queries-sql-server/</guid><description>&lt;p&gt;I frequently need to see rowcounts and execution time for queries while they&amp;rsquo;re running. Maybe I&amp;rsquo;m troubleshooting a slow query that&amp;rsquo;s still executing, or I want to understand which operators are causing the slowdown before the query completes.&lt;/p&gt;
&lt;p&gt;Last week at the &lt;a href="https://passdatacommunitysummit.com/"&gt;PASS Summit&lt;/a&gt; I learned some little nuances about how this works that I&amp;rsquo;d missed.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/standard_query_profiling_nested_loop.jpg"
alt="Execution plan showing nested loop operator with rowcounts and timing information" width="250"&gt;
&lt;/figure&gt;
&lt;h2 id="tldr-quick-method"&gt;Tldr: Quick Method&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;For application queries&lt;/strong&gt;: Use &lt;a href="https://github.com/amachanic/sp_whoisactive"&gt;&lt;code&gt;sp_WhoIsActive&lt;/code&gt;&lt;/a&gt; with &lt;code&gt;@get_plans = 1&lt;/code&gt; to see rowcounts for in-flight queries. Rowcounts show up even if the session running the query doesn&amp;rsquo;t have standard profiling enabled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When reproducing a slow query from my own session&lt;/strong&gt;: Enable actual execution plans (Ctrl+M) in the session running the query, then use &lt;a href="https://github.com/amachanic/sp_whoisactive"&gt;&lt;code&gt;sp_WhoIsActive&lt;/code&gt;&lt;/a&gt; with &lt;code&gt;@get_plans = 1&lt;/code&gt; in another session if it runs long. This includes not only rowcounts per operator, but also query execution times per operator in the in-flight plan that you nab.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_plans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to save a script for this, you can use &lt;code&gt;SET STATISTICS XML ON&lt;/code&gt; in the script that is running the query you want to profile instead of enabling actual execution plans in that session.&lt;/p&gt;
&lt;h2 id="my-misunderstanding"&gt;My Misunderstanding&lt;/h2&gt;
&lt;p&gt;I used to think that execution times per operator showing up in &lt;code&gt;sp_WhoIsActive&lt;/code&gt; was random. The rowcounts pretty much always show up on recent versions of SQL Server, but sometimes I&amp;rsquo;d see execution times per operator, sometimes I wouldn&amp;rsquo;t. It seemed like luck.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d missed the memo that execution times per operator only appear when standard query profiling is enabled in the session running the query. It&amp;rsquo;s not random at all. I was enabling it without realizing it—when I had already enabled actual execution plans on queries I was running for repro, that automatically enabled standard query profiling.&lt;/p&gt;
&lt;p&gt;Standard query profiling enables additional runtime statistics collection. When enabled, SQL Server collects execution times per operator as the query runs. Rowcounts are available even without standard profiling enabled, but execution times per operator require it.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/amachanic/sp_whoisactive"&gt;&lt;code&gt;sp_WhoIsActive&lt;/code&gt;&lt;/a&gt; queries the &lt;code&gt;sys.dm_exec_query_statistics_xml&lt;/code&gt; dynamic management view, which &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-statistics-xml-transact-sql"&gt;returns the query execution plan for in-flight requests with transient statistics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Query this DMV directly if you can&amp;rsquo;t install &lt;code&gt;sp_WhoIsActive&lt;/code&gt; or prefer a simple approach:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eqs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.[&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait_resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu_time_sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cpu_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logical_reads_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;granted_memory_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;granted_query_memory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan_hash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_requests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_query_statistics_xml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eqs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;SPID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="lets-look-at-this-in-action"&gt;Let&amp;rsquo;s Look at This in Action&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a script that takes a bit of time to run, which can be useful for testing this against the StackOverflow2013 sample database. This drops any nonclustered indexes and auto-created stats that exist, then creates two nonclustered indexes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DropIndexes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Reputation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId_OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After I get those index creation operations running in one session, I run the query above in a second session to capture the in-flight plan.&lt;/p&gt;
&lt;p&gt;I do NOT have actual execution plans enabled on the query that is creating the indexes, so the in-flight plan has rowcounts on each operator, but no timing information:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/in-flight-query-results-rowcounts-no-timing.jpg"
alt="Execution plan showing rowcounts for each operator but no timing information, captured from an in-flight query without standard query profiling enabled"&gt;
&lt;/figure&gt;
&lt;p&gt;In this execution plan, you can see rowcounts on each operator showing how many rows have been processed so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;[Clustered Index Scan]&lt;/strong&gt;: 16,677,114 rows processed (97% of 17,142,200 estimated), 92% estimated cost&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[Sort]&lt;/strong&gt;: 0 rows processed, 7% estimated cost&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[Online Index Insert]&lt;/strong&gt;: 0 rows processed, 1% estimated cost&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I rerun this process but first run &lt;code&gt;SET STATISTICS XML ON;&lt;/code&gt; or enable actual execution plans in the session that is creating the indexes, I additionally see execution time per operator in the in-flight plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/in-flight-query-results-rowcounts-and-timing.jpg"
alt="Execution plan showing both rowcounts and execution time per operator, captured from an in-flight query with standard query profiling enabled"&gt;
&lt;/figure&gt;
&lt;p&gt;With standard query profiling enabled, each operator shows both rowcounts and timing information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;[Clustered Index Scan]&lt;/strong&gt;: 14,901,911 rows processed (86% of 17,142,200 estimated), 11.607 seconds elapsed, 92% estimated cost&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[Sort]&lt;/strong&gt;: 0 rows processed, 13.813 seconds elapsed, 7% estimated cost&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[Online Index Insert]&lt;/strong&gt;: 0 rows processed, 13.813 seconds elapsed, 1% estimated cost&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="practical-tips"&gt;Practical Tips&lt;/h2&gt;
&lt;p&gt;Use this technique when troubleshooting slow queries or understanding query progress. It&amp;rsquo;s particularly helpful for identifying which operators are causing slowdowns before a query completes.&lt;/p&gt;
&lt;p&gt;Note that cost estimates in the plan (which show as percentages) are estimates made at the time the query was compiled. These cost estimates are NOT updated during or after runtime of the query. Queries may also reuse an execution plan where the cost estimates were made previously for a different query execution, based on the parameters that were sniffed when the plan was compiled.&lt;/p&gt;
&lt;p&gt;For more details on the query profiling infrastructure, see &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/query-profiling-infrastructure"&gt;Microsoft&amp;rsquo;s documentation&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Three Reasons RDS SQL Server Is Better Than Azure SQL Managed Instance</title><link>https://kendralittle.com/2025/10/08/three-differentiators-rds-sql-server-managed-database-cloud/</link><pubDate>Wed, 08 Oct 2025 14:25:57 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/10/08/three-differentiators-rds-sql-server-managed-database-cloud/</guid><description>&lt;p&gt;While every managed database service has high points and low points, there are three things that make RDS for SQL Server shine in comparison to Azure SQL Managed Instance: options for a higher memory:vCPU ratio, a well documented API that works beautifully with python, and fast and effective customer support that isn&amp;rsquo;t painful to use.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s just three things, but they make a huge difference. And these are three things that Microsoft can, and SHOULD, really fix for their cloud database services.&lt;/p&gt;
&lt;!--more --&gt;
&lt;h2 id="sql-server-rds-offers-a-high-memoryvcpu-ratio-which-really-matters-for-oltp-workloads"&gt;SQL Server RDS Offers a High Memory:vCPU Ratio, Which Really Matters for OLTP Workloads&lt;/h2&gt;
&lt;p&gt;AWS offers a variety of &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.Types.html"&gt;database instance class types for RDS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The standout among these for SQL Server OLTP workloads is the &lt;a href="https://aws.amazon.com/blogs/database/run-amazon-rds-for-sql-server-2x-faster-with-x2iedn-instances/"&gt;db.x2iedn instance class&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The db.x2iedn class offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;32GB:1 ratio of memory to virtual CPU&lt;/li&gt;
&lt;li&gt;Local SSD for tempdb&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the &lt;a href="https://aws.amazon.com/blogs/database/run-amazon-rds-for-sql-server-2x-faster-with-x2iedn-instances/"&gt;documentation says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The X2 instance family provides the highest memory to vCPU ratio compared to all supported RDS DB instance types. This is ideal for SQL Server workloads that are sensitive to per-core licensing, such as SQL Server Enterprise edition and SQL Standard Edition. Your workload can benefit greatly from the higher memory per vCPU (32GiB:1vCPU) offered by X2iedn and reduce the number of vCPU provisioned.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No lies detected&amp;ndash; this is good advice. SQL Server per-core licensing is &lt;strong&gt;expensive&lt;/strong&gt;, and SQL Server OLTP workloads massively benefit from having large amounts of memory to reduce the amount of physical IO. No matter what storage type we are talking about, memory access is always dramatically faster than storage access, and SQL Server is engineered to maximize and optimize the use of the buffer pool and other caches to reduce IO. A SQL Server loves memory like I love making lists: I can live without it, but performance significantly suffers.&lt;/p&gt;
&lt;p&gt;One problem with managed SQL Servers in the cloud in general is that memory to core ratios SUCK out there. In Azure, if you use &amp;ldquo;memory optimized&amp;rdquo; hardware, you can get &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits?view=azuresql#hardware-configuration-characteristics"&gt;up to 13.6GB:1 memory to vCPU ratio max&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you pay the big bucks for Business Critical, you can get local SSD, but I repeat: &lt;strong&gt;memory access is always dramatically faster than storage access, and SQL Server is engineered to maximize and optimize the use of the buffer pool and other caches to reduce IO&lt;/strong&gt;. 13.6:1 is &lt;em&gt;very disappointing&lt;/em&gt;, and Microsoft should do much better to compete on this.&lt;/p&gt;
&lt;h2 id="the-benefits-of-a-well-documented-api-that-works-well-with-python"&gt;The Benefits of a Well Documented API That Works Well with Python&lt;/h2&gt;
&lt;p&gt;I wanted to love using PowerShell for Managed Instance. I&amp;rsquo;m a huge believer in automation and in scripting out tasks for repeatability and reducing manual toil. I did OK with the API for Managed Instance, but just OK. There were always weird things that weren&amp;rsquo;t documented correctly or which were hard to get to work. Using LLMS to generate code had similar problems that I did due to gaps in the documentation. It wasn&amp;rsquo;t terrible, but it was often frustrating.&lt;/p&gt;
&lt;p&gt;Using python to automate tasks with the RDS API has been a lot easier. I started out with a very basic knowledge of python &amp;ndash; similar to my PowerShell knowledge. But python has some big advantages: it&amp;rsquo;s quite readable, and LLMs are optimized to do well with python. The RDS API&amp;rsquo;s documentation is also pretty darn clear and LLMs seem to be well trained on AWS APIs.&lt;/p&gt;
&lt;p&gt;Like any generated code: review, review, review, and test. Then review some more. You have to be extremely careful. But the readability of python and the fact that LLMs are well trained in this area are a powerful combo to work with, and it&amp;rsquo;s quite fun to script tasks for the RDS API.&lt;/p&gt;
&lt;p&gt;Y&amp;rsquo;all, working with python with AWS&amp;rsquo; APIs is like having a superpower.&lt;/p&gt;
&lt;h2 id="fast-and-effective-customer-support-that-isnt-painful-to-use"&gt;Fast and Effective Customer Support That Isn&amp;rsquo;t Painful to Use&lt;/h2&gt;
&lt;p&gt;I wrote a blog post last year titled &lt;a href="https://kendralittle.com/2024/09/23/how-survive-microsoft-support-ticket-sql-server-azure-sql/"&gt;How to survive opening a Microsoft support ticket for SQL Server or Azure SQL&lt;/a&gt;. It truly sucked to be an Azure customer when I had a problem.&lt;/p&gt;
&lt;p&gt;The experience of being an Azure SQL Managed Instance customer is that you constantly feel like the support system is trying to deflect you and get rid of you. You feel that the machine is trying to give you any possible answer, whether or not it&amp;rsquo;s correct, to make you go away as quickly as possible. In order to get quality help, you&amp;rsquo;ve got to battle various levels of bad advice until you finally get to someone who has time to figure out what&amp;rsquo;s going on. The system feels optimized primarily to deflect and minimize costs.&lt;/p&gt;
&lt;p&gt;The experience of being a SQL Server RDS customer is that you feel like the support system is optimized to help unblock you as soon as possible so that you can successfully use more RDS SQL Server. You have both a client team who can help you and then folks you work with through the ticketing system, and these folks can work together. There is some paperwork occasionally and some waiting sometimes, but by comparison it works pretty darn effectively most of the time. I don&amp;rsquo;t dread opening a support case at all.&lt;/p&gt;
&lt;p&gt;Smart people work in both of these systems. And both of these systems are optimized around profit: Azure feels like it&amp;rsquo;s trying to reduce costs, AWS feels like it wants to help you spend more. That second experience is a lot more effective and pleasant for customers.&lt;/p&gt;
&lt;p&gt;The problems with Azure support aren&amp;rsquo;t about the employees who provide the support: it&amp;rsquo;s that the system very much feels to the customer like it&amp;rsquo;s a cost center that is trying to be squeezed down to the cheapest penny. I don&amp;rsquo;t think this serves Microsoft well, and it certainly doesn&amp;rsquo;t help them sell more managed database services to existing customers.&lt;/p&gt;
&lt;h2 id="microsoft-please-start-to-compete-on-these"&gt;Microsoft, Please Start to Compete on These&lt;/h2&gt;
&lt;p&gt;As a database person, I want cloud options for managed databases to be more competitive with each other on the basics: performance, automation, and customer service. Right now, for managed SQL Servers in the cloud, AWS RDS has a much better offering for performance and management because of the reasons above.&lt;/p&gt;
&lt;p&gt;But these are all very fixable things. Microsoft can make their offerings much stronger in this area, and I hope that they make the investments needed to do so.&lt;/p&gt;</description></item><item><title>Why Won't PostgreSQL Use My Covering Index?</title><link>https://kendralittle.com/2025/06/26/why-wont-postgresql-use-covering-index/</link><pubDate>Thu, 26 Jun 2025 19:43:14 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/06/26/why-wont-postgresql-use-covering-index/</guid><description>&lt;p&gt;Dear Postgres, Why won&amp;rsquo;t you use my covering index?&lt;/p&gt;
&lt;p&gt;Lately I&amp;rsquo;ve been learning to tune queries running against PostgreSQL, and it&amp;rsquo;s pretty delightful. One fun question that I worked through struck me something that most Postgres users probably encounter one way or another: sometimes you may create the &lt;em&gt;perfect&lt;/em&gt; index that covers a given query, but the query planner will choose to ignore it and scan the base table.&lt;/p&gt;
&lt;p&gt;Why in the world would it do that?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/RabbitCordCutter.jpg" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="the-perfect-index"&gt;The Perfect Index&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you have a relatively large table &amp;ndash; something like the Posts table in the Stack Overflow database. You want to run a query to count the number of posts that are questions created after a specific date that have an AnswerCount of 0.&lt;/p&gt;
&lt;p&gt;The query for this would use multiple columns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PostTypeId with an equality predicate (Questions have PostTypeId=1)&lt;/li&gt;
&lt;li&gt;AnswerCount with an equality predicate (AnswerCount = 0)&lt;/li&gt;
&lt;li&gt;CreationDate with a range predicate (&amp;gt; Date Value)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To &amp;ldquo;cover&amp;rdquo; this query, you create a btree index on the table with the index keys PostTypeId, AnswerCount, and CreationDate, in that order.&lt;/p&gt;
&lt;p&gt;This index is built and is a nice, beautiful structure with all of those columns. This structure is ordered so that all the rows where PostTypeId = 1 are together, then they are ordered by AnswerCount, so we can quickly find everything where AnswerCount = 0 for our questions. The third ordering column is CreationDate, so we can seek and find all the rows greater than the value we are looking for and count them.&lt;/p&gt;
&lt;p&gt;This index seems to cover everything we need in the query.&lt;/p&gt;
&lt;h2 id="but-it-might-not-get-used"&gt;But It Might Not Get Used&lt;/h2&gt;
&lt;p&gt;I had a situation similar to this: I created the ideal index for a simple query. Then I asked Postgres for an explain plan&amp;ndash; basically to run the query and show me how it executed it with some details.&lt;/p&gt;
&lt;p&gt;It did so, and showed me that it didn&amp;rsquo;t use my index: instead, it scanned the base table with a sequential scan.&lt;/p&gt;
&lt;p&gt;I re-checked my index. IT WAS PERFECT. I ran the explain plan again &amp;ndash; maybe I was mistaken? Nope, sequential scan against the heap.&lt;/p&gt;
&lt;h2 id="what-if-i-force-it-to-use-it"&gt;What If I Force It to Use It?&lt;/h2&gt;
&lt;p&gt;PostgreSQL has &lt;a href="https://www.postgresql.org/docs/current/runtime-config-query.html#RUNTIME-CONFIG-QUERY-CONSTANTS"&gt;some costing settings that influence whether the query planner chooses to use nonclustered indexes&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;seq_page_cost&lt;/code&gt;: &amp;ldquo;Sets the planner&amp;rsquo;s estimate of the cost of a disk page fetch that is part of a series of sequential fetches. The default is 1.0.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;random_page_cost&lt;/code&gt;: &amp;ldquo;Sets the planner&amp;rsquo;s estimate of the cost of a non-sequentially-fetched disk page. The default is 4.0. &amp;hellip;Reducing this value relative to seq_page_cost will cause the system to prefer index scans; raising it will make index scans look relatively more expensive.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, my index was &lt;em&gt;perfect&lt;/em&gt; in my mind, but I went ahead and ran &lt;code&gt;SET random_page_cost = 1.1;&lt;/code&gt; to change this for my session.&lt;/p&gt;
&lt;p&gt;I then re-ran explain analyze for my query and I saw that PostgreSQL used my index.&lt;/p&gt;
&lt;p&gt;But I also saw that the execution time for my query was much slower than it had taken to generate the explain analyze plan that used the sequential scan of the table.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d forced the query planner to use my index, but &lt;em&gt;it made the query slower&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="where-did-this-random-io-come-from"&gt;Where did This Random IO Come From?&lt;/h2&gt;
&lt;p&gt;Thinking a little about the setting I&amp;rsquo;d tweaked, I realized that I&amp;rsquo;d only gotten the query planner to use the index by saying that random IO was not such a big deal. It clearly had rejected the index because it didn&amp;rsquo;t want to do random IO.&lt;/p&gt;
&lt;p&gt;So why wasn&amp;rsquo;t the index &amp;ldquo;covering&amp;rdquo; my query? What would it need outside of the index?&lt;/p&gt;
&lt;p&gt;This is covered nicely in the docs on &lt;a href="https://www.postgresql.org/docs/current/indexes-index-only-scans.html"&gt;Index-Only Scans and Covering Indexes&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But there is an additional requirement for any table scan in PostgreSQL: it must verify that each retrieved row be “visible” to the query&amp;rsquo;s MVCC snapshot, as discussed in Chapter 13. Visibility information is not stored in index entries, only in heap entries&amp;hellip;&lt;/p&gt;
&lt;p&gt;PostgreSQL tracks, for each page in a table&amp;rsquo;s heap, whether all rows stored in that page are old enough to be visible to all current and future transactions. This information is stored in a bit in the table&amp;rsquo;s visibility map. An index-only scan, after finding a candidate index entry, checks the visibility map bit for the corresponding heap page. If it&amp;rsquo;s set, the row is known visible and so the data can be returned with no further work. If it&amp;rsquo;s not set, the heap entry must be visited to find out whether it&amp;rsquo;s visible, so no performance advantage is gained over a standard index scan.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was querying a table where a significant amount of data has been changed, and I was running a query that was going to look at a lot of rows.&lt;/p&gt;
&lt;p&gt;When I had a higher value for &lt;code&gt;random_page_cost&lt;/code&gt;, the query planner realized that it could use the nonclustered index to seek to the data, but that it was going to have to check a whole lot of of corresponding heap pages, which was a lot of random IO.&lt;/p&gt;
&lt;h2 id="tidying-up-my-tuples"&gt;Tidying Up My Tuples&lt;/h2&gt;
&lt;p&gt;Vacuuming is the process in Postgres that helps with this. &lt;a href="https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-BASICS"&gt;Vacuumming Basics&lt;/a&gt; explains that the vacuum process is essential for multiple purposes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;To recover or reuse disk space occupied by updated or deleted rows.&lt;/li&gt;
&lt;li&gt;To update data statistics used by the PostgreSQL query planner.&lt;/li&gt;
&lt;li&gt;To update the visibility map, which speeds up index-only scans.&lt;/li&gt;
&lt;li&gt;To protect against loss of very old data due to transaction ID wraparound or multixact ID wraparound.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Item 3 &amp;ndash; that&amp;rsquo;s our issue.&lt;/p&gt;
&lt;p&gt;Sure enough, I looked at the tables used by my query and realized that although the autovacuum process was enabled, the default thresholds were high enough that a whole lot of data had changed in this table without the process kicking in.&lt;/p&gt;
&lt;p&gt;I ran a manual vacuum against the table and found that executing my query was now much faster when it used the nonclustered index, and that the query planner was willing to use the nonclustered index when my session had higher values for &lt;code&gt;random_page_cost&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll dig in more in future posts on considerations I&amp;rsquo;ve found with tweaking these settings, as well as autovacuum and autoanalyze settings.&lt;/p&gt;</description></item><item><title>Fixing OPTIMIZATION REPLAY FAILED in Query Store: When Plan Forcing Breaks in SQL Server 2022+</title><link>https://kendralittle.com/2025/04/30/fix_optimization_replay_failed_plan_forcing_sql_server_query_store/</link><pubDate>Wed, 30 Apr 2025 11:04:28 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/04/30/fix_optimization_replay_failed_plan_forcing_sql_server_query_store/</guid><description>&lt;p&gt;Forcing plans with Query Store can be a powerful tool— until it mysteriously fails. In real production systems, plan forcing sometimes just… doesn’t work. One common culprit is the cryptic &lt;code&gt;OPTIMIZATION_REPLAY_FAILED&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re hitting &lt;code&gt;OPTIMIZATION_REPLAY_FAILED,&lt;/code&gt; try re-forcing the plan using &lt;code&gt;@disable_optimized_plan_forcing=1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="the-syntax-you-may-be-looking-for"&gt;The Syntax You May Be Looking For&lt;/h2&gt;
&lt;p&gt;How to force a query plan without optimization replay:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xxx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yyy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;disable_optimized_plan_forcing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Won&amp;rsquo;t it be great if Query Store on secondaries ever becomes a supported thing and we can use the @force_plan_scope parameter?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="quick-recap-of-failed-forced-plans"&gt;Quick Recap of Failed Forced Plans&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/replay.jpg" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;Sometimes when you force a query plan, SQL Server has a problem enforcing the forcing. If plan forcing fails, the query still executes successfully:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;When a plan is forced for a particular query, every time SQL Server encounters the query, it tries to force the plan in the Query Optimizer. If plan forcing fails, an Extended Event is fired and the Query Optimizer is instructed to optimize in the normal way.&amp;rdquo; (&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-query-store-force-plan-transact-sql"&gt;docs for sp_query_store_force_plan&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When query plan forcing fails, the &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-store-plan-transact-sql"&gt;sys.query_store_plan&lt;/a&gt; view will contain some value for &lt;code&gt;last_force_failure_reason_desc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There is no benefit from leaving a query in a state where plan forcing is failing, so I&amp;rsquo;ve &lt;a href="https://kendralittle.com/2024/09/02/free-script-automate-unforcing-failed-forced-plans-query-store-sql-server/"&gt;shared a script that finds and un-forces failed plans&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve implemented versions of this that log the queries/plans found in a failed forced state along with the reason why plan forcing failed.&lt;/p&gt;
&lt;p&gt;Many of those queries have &lt;code&gt;OPTIMIZATION_REPLAY_FAILED&lt;/code&gt; as the reason.&lt;/p&gt;
&lt;h2 id="optimization-replay-is-automatically-on-in-sql-server-2022-even-if-youre-not-at-database-compatibility-level-160"&gt;Optimization Replay is Automatically on in SQL Server 2022+, Even If You&amp;rsquo;re Not at Database Compatibility Level 160&lt;/h2&gt;
&lt;p&gt;In my opinion, that error message should say &lt;code&gt;OPTIMIZED_PLAN_FORCING_FAILED&lt;/code&gt;, because &amp;ldquo;optimization replay&amp;rdquo; is part of the feature named &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/optimized-plan-forcing-query-store"&gt;Optimized plan forcing&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Optimized plan forcing reduces compilation overhead for repeating forced queries&amp;hellip; Once the query execution plan is generated, specific compilation steps are stored for reuse as an optimization replay script.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Optimized plan forcing (aka optimization replay) occurs in SQL Server 2022 and higher. It is enabled by default and works even if you are using a lower database compatibility level &amp;ndash; for example, I regularly see this on SQL Server 2022 with db compat level 150.&lt;/p&gt;
&lt;h2 id="three-ways-to-disable-optimized-replay"&gt;Three Ways to Disable Optimized Replay&lt;/h2&gt;
&lt;p&gt;You can disable optimized plan forcing/ optimized replay in three different ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the query level, using the &lt;code&gt;DISABLE_OPTIMIZED_PLAN_FORCING&lt;/code&gt; query hint&lt;/li&gt;
&lt;li&gt;At the database level, using a database scoped configuration (aka disable with &lt;code&gt;ALTER DATABASE SCOPED CONFIGURATION SET OPTIMIZED_PLAN_FORCING = OFF&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;When forcing a query plan by using the &lt;code&gt;sys.sp_query_store_force_plan&lt;/code&gt; stored procedure with &lt;code&gt;@disable_optimized_plan_forcing=1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wish that when one forced a plan and there was an issue with the replay script, SQL Server would simply fall back to not using a replay script for plan forcing for that query. That doesn&amp;rsquo;t happen &amp;ndash; you need to TRY to force a plan, then detect if plan forcing fails and for what reason. If you find it&amp;rsquo;s an optimization replay issue, you need to try to re-force the plan with a different parameter.&lt;/p&gt;
&lt;p&gt;Or, if you don&amp;rsquo;t have time for all that, you can disable optimized plan forcing at the database level.&lt;/p&gt;
&lt;h2 id="what-if-its-general_failure"&gt;What If It&amp;rsquo;s GENERAL_FAILURE?&lt;/h2&gt;
&lt;p&gt;If query plan forcing is failing with the message &lt;code&gt;GENERAL_FAILURE&lt;/code&gt;, &lt;a href="https://kendralittle.com/2024/08/12/query-store-failed-forced-plans-general-failure-even-slower-compile-time/"&gt;check out my post on that topic&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;If plan forcing fails with &lt;code&gt;OPTIMIZATION_REPLAY_FAILED&lt;/code&gt;, re-force the plan using&lt;code&gt; @disable_optimized_plan_forcing=1&lt;/code&gt;. It&amp;rsquo;s common in SQL Server 2022+, even at lower compatibility levels. Always check &lt;code&gt;last_force_failure_reason_desc&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Comparing Single Column, Multi-Column, and Filtered Statistics in SQL Server</title><link>https://kendralittle.com/2025/04/13/single-multi-column-filtered-statistics/</link><pubDate>Sun, 13 Apr 2025 14:04:35 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/04/13/single-multi-column-filtered-statistics/</guid><description>&lt;p&gt;Statistics in SQL Server are simple in theory: they help the optimizer estimate how many rows a query might return.&lt;/p&gt;
&lt;p&gt;In practice? Things get weird fast. Especially when you start filtering on multiple columns, or wondering why the optimizer thinks millions of rows are coming back when you know it’s more like a few hundred thousand.&lt;/p&gt;
&lt;p&gt;In this post, I’ll walk through examples using single-column, multi-column, and filtered statistics—and show where estimates go off the rails, when they get back on track, and why that doesn’t always mean you need to update everything with FULLSCAN.&lt;/p&gt;
&lt;!--more --&gt;
&lt;h2 id="im-using-the-stackoverflow2013-sample-database-at-compat-level-160"&gt;I&amp;rsquo;m Using the Stackoverflow2013 Sample Database at Compat Level 160&lt;/h2&gt;
&lt;p&gt;To get started, I&amp;rsquo;ve dropped all my existing indexes and statistics. I&amp;rsquo;ve created a helper object that lists all the statistics on a given table.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListStatistics&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ObjectName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysname&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statistic_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;leading_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;auto_created&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auto_created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_created&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;has_filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filter_definition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;no_recompute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_recompute&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_column_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ObjectName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before I get started, the &lt;code&gt;dbo.Posts&lt;/code&gt; table has a single statistic.&lt;/p&gt;
&lt;p&gt;This statistic is associated with the clustered index on the &lt;code&gt;Id&lt;/code&gt; column. Whenever an index is created in SQL Server, a statistic is created along with that index.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_clustered_index.png"&gt;
&lt;/figure&gt;
&lt;h2 id="run-our-example-query-which-will-auto-create-single-column-statistics-to-help-with-estimates"&gt;Run Our Example Query, Which Will Auto-create Single Column Statistics to Help with Estimates&lt;/h2&gt;
&lt;p&gt;Our example query has three predicates, on &lt;code&gt;PostTypeId&lt;/code&gt;, &lt;code&gt;ParentId&lt;/code&gt;, and &lt;code&gt;AnswerCount&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To simplify things so auto-parameterization and query plan reuse don&amp;rsquo;t involved, I&amp;rsquo;ve added an &lt;code&gt;OPTION (RECOMPILE)&lt;/code&gt; hint to the query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When I give this a run, the query plan shows&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL Server estimates that 3,200,270 rows will be returned.&lt;/li&gt;
&lt;li&gt;305,761 rows are actually returned&amp;ndash; only 9.5% of what was estimated. That estimate was very high.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_query_estimated_actual_single_column_statistics.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;I re-run &lt;code&gt;dbo.ListStatistics&lt;/code&gt; and see that three column statistics were automatically created, one on each of the three predicates in my query. I have the &lt;code&gt;AUTO_CREATE_STATISTICS&lt;/code&gt; setting enabled for the StackOverflow2013 database&amp;ndash; that&amp;rsquo;s a default setting, and it allows SQL Server to create these small helper objects to put together this estimate.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_3_auto_created_column_statistics.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Each of these statistics took a sampling of rows from the table and used that sampling to create a histogram with &amp;ldquo;steps&amp;rdquo; describing what values are in the table and how many rows exist for some values. This is stored along with metadata: how many rows were in the table at the time of the sampling? How many rows were sampled? About how many unique values exist in the column?&lt;/p&gt;
&lt;p&gt;For example, here is a view of the histogram for the automatically created single column statistic on the PostTypeId column:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_histogram_posttypeid.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Based on a sampling of the data, there were estimated to be 5,977,672 rows in dbo.Posts with PostTypeId=1 at the time the statistic was auto-created.&lt;/p&gt;
&lt;p&gt;The column statistics created for ParentId and AnswerCount similarly describe how data is distributed in those columns.&lt;/p&gt;
&lt;p&gt;SQL Server can use these statistics to make estimates, but note that none of these statistics describe data distributions for all three columns when they are used together.&lt;/p&gt;
&lt;h2 id="when-we-create-an-index-with-multiple-key-columns-it-creates-a-multi-column-statistic-to-go-with-it"&gt;When We Create an Index with Multiple Key Columns, It Creates a Multi-column Statistic to Go with It&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say we have an index on the first two columns in our predicate. Here&amp;rsquo;s the index:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Posts_PostTypeId_ParentId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve created a nonclustered index that does not fully &amp;ldquo;cover&amp;rdquo; my query: it has two out of three predicates.&lt;/p&gt;
&lt;p&gt;I run my query again, and SQL Server does not choose to use my new index. Its row estimate is slightly different:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before, SQL Server had estimated 3,200,270 rows would be returned.&lt;/li&gt;
&lt;li&gt;Now, SQL Server estimates 3,212,350 rows will be returned (12,080 more)&lt;/li&gt;
&lt;li&gt;This estimate is still very high, only 305,761 rows are returned (the same, rows in the database are not changing)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_query_estimated_actual_multi_column_index_statistic.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Why is this estimate just a little bit higher?&lt;/p&gt;
&lt;p&gt;If I use &lt;code&gt;DBCC SHOW_STATISTICS&lt;/code&gt; to describe the statistic associated with the index, it does describe a &lt;em&gt;little bit&lt;/em&gt; about more than the first column, but not much. Important things to notice are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This statistic was created when SQL Server created the index, and it had to look at every row in the column to do that. It used that information from all the rows (rather than a sampling), so the data in the statistic is a little different.&lt;/li&gt;
&lt;li&gt;The statistic has a &amp;ldquo;Density vector&amp;rdquo; section, which describes the average selectivity of column values—in other words, how distinct the values tend to be.
&lt;ul&gt;
&lt;li&gt;It gives the inverse of the number of distinct (PostTypeId, ParentId) pairs.&lt;/li&gt;
&lt;li&gt;For example, if the all density value is 1.779737E-07, that implies there are about 5.6 million distinct (PostTypeId, ParentId) combinations (1/.0000001779737= 5,618,807).
&lt;ul&gt;
&lt;li&gt;There are 1,7142,169 rows in the table, which implies that any given PostTypeId, ParentId column has about 3.05 rows for it IF there is a very even distribution of values.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The histogram of the statistic is only on the leading column in the index, which in this case is PostTypeId. PostTypeId has a pretty limited set of values.
&lt;ul&gt;
&lt;li&gt;The histogram shows 6,000,223 values for PostTypeId = 1. In the column statistic on PostTypeId that was based on sampling, this estimate was 5,977,672. The estimate has gone up by 22,551.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_query_statistic_index_multiple_columns.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;In this case, it looks like the fact that we have a multi-column statistic didn&amp;rsquo;t really give the optimizer too much new information it thought was useful.&lt;/p&gt;
&lt;p&gt;Yes, the density vector implies that there are 3.05 rows on average for any given combination of PostTypeId and ParentId values on average, but the estimate is way higher than 3 rows. It looks like our estimate is still based on histogram values, and the estimate went up a little bit because the histogram for the new index&amp;ndash; which is only on the leading column, PostTypeId&amp;ndash; estimated a slightly higher number of rows for PostTypeId = 1.&lt;/p&gt;
&lt;h2 id="create-a-multi-column-filtered-statistic-tailored-to-the-query"&gt;Create a Multi-column Filtered Statistic Tailored to the Query&lt;/h2&gt;
&lt;p&gt;Now, I could create a multi-column filtered index that is perfect for my query. But let&amp;rsquo;s say that this query doesn&amp;rsquo;t run that often, and I don&amp;rsquo;t want to create an index just for it. However, I want to see if SQL Server might be smarter if I gave it a statistic.&lt;/p&gt;
&lt;p&gt;I create a statistic that is very targeted for my query, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATISTICS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FilteredStats_Posts_PostTypeId_ParentId_AnswerCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostTypeId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ParentId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing I&amp;rsquo;ve noticed is that when you create a statistic like this, it won&amp;rsquo;t automatically make queries recompile. I have an &lt;code&gt;OPTION (RECOMPILE)&lt;/code&gt; clause in my query, though, so I don&amp;rsquo;t have to worry about that.&lt;/p&gt;
&lt;p&gt;Rerunning my query, I get the same shape plan, but the estimates are much more accurate:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_query_statistic_filtered.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;With the filtered multi-column statistic, SQL Server is estimating that 306,267 will be returned, very close to the actual rowcount of 305,761.&lt;/p&gt;
&lt;p&gt;This doesn&amp;rsquo;t make much of a difference in this simple case, but if I was joining to this table and the data was flowing into an operator that needed to allocate memory, like a hash join or a sort, this estimate could make a difference.&lt;/p&gt;
&lt;p&gt;Real world talk: I don&amp;rsquo;t go around creating statistics like this &amp;ldquo;just in case&amp;rdquo;, and I wouldn&amp;rsquo;t assume that this will automatically solve a problem&amp;ndash; but sometimes this can help in a specific situation where it doesn&amp;rsquo;t make sense to create an index and poor row estimates are causing a performance problem.&lt;/p&gt;
&lt;h2 id="the-query-plan-depends-on-which-version-of-the-cardinality-estimator-ce-im-using"&gt;The Query Plan Depends on Which Version of the Cardinality Estimator (CE) I&amp;rsquo;m Using&lt;/h2&gt;
&lt;p&gt;SQL Server has two cardinality estimators: the &amp;ldquo;legacy&amp;rdquo; cardinality estimator, which applies to database compatibility level 110 and below (or if you have it enabled as a &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-scoped-configuration-transact-sql"&gt;database scoped configuration&lt;/a&gt;), and the &amp;ldquo;doesn&amp;rsquo;t really have a name&amp;rdquo;/newer cardinality estimator.&lt;/p&gt;
&lt;p&gt;The legacy cardinality estimator is more likely to assume that data distributions on different columns &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/cardinality-estimation-sql-server"&gt;are independent of one another&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If I have the filtered statistic created and the two column index created, and I run my query using the legacy cardinality estimator, SQL Server decides to use the non-covering index and do a nested loop lookup to pick up the AnswerCount data (which is not in the index).&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistic_post_query_statistic_filtered-legacy-ce.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The row estimate for how much will come out of the nested loop operator is very accurate: 306,267 rows (actual is 305,761).&lt;/p&gt;
&lt;p&gt;However, SQL Server estimates that 750,710 rows will come out of the index on &lt;code&gt;PostTypeId&lt;/code&gt;, &lt;code&gt;ParentId&lt;/code&gt;, whereas it actually had 6,000,223 rows returned from the operator.&lt;/p&gt;
&lt;h2 id="tips-and-takeaways-about-statistics"&gt;Tips and Takeaways About Statistics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Statistics help SQL Server guess row counts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Statistics are estimates, and close-enough is usually fine. Don’t chase perfection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Auto-created single-column stats have a histogram that describes how data is distributed in one column at a time. If your query filters on multiple columns, SQL Server has to guess how those filters work together.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multi-column stats (created with multi-column indexes, or manually) only have a histogram for the leading column.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filtered statistics can help with tricky queries where the estimate is way off and you don’t want (or need) a new index. If you match the filter exactly, the estimate can get much better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don&amp;rsquo;t assume “bad estimate” means “bad stat” or &amp;ldquo;bad plan&amp;rdquo;. Estimates can be off and still lead to a good plan. Make sure to verify if your problem has to do with &amp;ldquo;statistics were wrong&amp;rdquo; or if it&amp;rsquo;s a case of &amp;ldquo;the statistics were fine for the values the query plan was compiled with, but then the plan ran with different values for parameters&amp;rdquo; (a parameter sniffing problem).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid the “just fullscan all your statistics” trap. Updating statistics with fullscan all the time burns IO and slows down over time. Becoming dependent upon this can leave you in a reactive position where you regularly have poor performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The version of the cardinality estimator matters. Sometimes the legacy cardinality will work better for a query. Sometimes it won&amp;rsquo;t.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>All Eyes on the Wrong Problem: How Mitigations Distract from Real Performance Pain</title><link>https://kendralittle.com/2025/04/06/acclimating-users-bad-makes-miss-truly-terrible/</link><pubDate>Sun, 06 Apr 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/04/06/acclimating-users-bad-makes-miss-truly-terrible/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: Microsoft has announced the general availability of the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;Next-gen General Purpose service tier&lt;/a&gt; for Azure SQL Managed Instance, which includes improvements to I/O latency, IOPS, and transaction log throughput. This post describes the original General Purpose blob storage. You don't want that.
&lt;/div&gt;
&lt;p&gt;The biggest lesson I&amp;rsquo;ve learned from helping folks manage data in Azure is this: if you&amp;rsquo;ve got a truly terrible problem you&amp;rsquo;d rather people didn&amp;rsquo;t notice, a great way to hide it is by educating your support staff and users about something &lt;em&gt;bad but not AS terrible&lt;/em&gt;— something with a small mitigation—and constantly refocusing them on that.&lt;/p&gt;
&lt;p&gt;The user base— and even your own support staff— will think that anyone who talks about the bigger issue just doesn’t understand how to fix the “known” problem.&lt;/p&gt;
&lt;p&gt;This is the story of Azure General Purpose storage for Azure SQL Managed Instance and Azure SQL Database.&lt;/p&gt;
&lt;h2 id="flaw-1-consistent-lousy-storage-performance"&gt;Flaw 1: Consistent Lousy Storage Performance&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the &amp;lsquo;really bad but you can mitigate it a little&amp;rsquo; thing about General Purpose storage in Azure SQL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the General Purpose service tier, every database file gets dedicated IOPS and throughput that depend on the file size. Larger files get more IOPS and throughput&amp;hellip;
There&amp;rsquo;s also an instance-level limit on the max log write throughput (see the previous table for values, for example 22 MiB/s), so you might not be able to reach the max file throughout on the log file because you&amp;rsquo;re hitting the instance throughput limit.
&lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits?view=azuresql#file-io-characteristics-in-general-purpose-tier"&gt;Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&amp;rsquo;s a table in the document above that describes the IOPs / throughput levels for files, and why you need to grow them to 130 GB, 514 GB, 1026 GB, or more.&lt;/p&gt;
&lt;p&gt;The larger your files, the more you pay, so this is not only inconvenient, but also expensive.&lt;/p&gt;
&lt;p&gt;If you contact Microsoft support with any question about storage performance, they will fixate on this weird, complex limitation.&lt;/p&gt;
&lt;p&gt;But this is far from the worst storage problem in Azure SQL General Purpose.&lt;/p&gt;
&lt;h2 id="flaw-2-intermittent-atrocious-storage-performance"&gt;Flaw 2: Intermittent Atrocious Storage Performance&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a footnote on the resource limits above, which reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1 This [Storage IO latency measurement] is an average range. Although the vast majority of IO request durations will fall under the top of the range, outliers which exceed the range are possible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s unclear what they mean by &amp;ldquo;vast majority&amp;rdquo;, but let&amp;rsquo;s be generous and say it&amp;rsquo;s 95% of requests. Now imagine that 5% of your database storage requests take more than 15 seconds to complete. In fact, I&amp;rsquo;ve observed this to be between 15 and 60 seconds. 60 &lt;strong&gt;seconds&lt;/strong&gt;. Serially.&lt;/p&gt;
&lt;p&gt;Stop and wait for 60 seconds. That&amp;rsquo;s a real long time.&lt;/p&gt;
&lt;p&gt;Now think about what happens when a storage request underneath a database waits that long. The query may be holding locks that block things. All sorts of activity may back up. Things get real, real bad.&lt;/p&gt;
&lt;p&gt;Even if it&amp;rsquo;s much smaller than 5%&amp;ndash; in fact I think on average this probably happens to a given database about 10 times a week &amp;ndash; you don&amp;rsquo;t want to run a database on storage like that. Not even an unimportant database. Particularly for what you pay for Azure SQL Database or Managed Instance.&lt;/p&gt;
&lt;p&gt;This is beyond alarming, but every time a Microsoft employee reads my post on how &lt;a href="https://kendralittle.com/2024/12/18/azure-sql-managed-instance-storage-regularly-slow-60-seconds/"&gt;Azure SQL Managed Instance Storage is Regularly as Slow as 60 Seconds&lt;/a&gt;, they send me an email, direct message, or leave me a comment about how I&amp;rsquo;ve missed the &amp;ldquo;bad&amp;rdquo; issue and that Azure SQL storage performance varies by file sizes. They don&amp;rsquo;t &lt;em&gt;ask&lt;/em&gt; if it&amp;rsquo;s related, either, they&amp;rsquo;re confident I&amp;rsquo;m ignorant of the issue and there&amp;rsquo;s a way to make this better. This happens so often that I&amp;rsquo;ve had to update the post to add an explicit disclaimer for Microsoft employees.&lt;/p&gt;
&lt;p&gt;In fact, the storage stall problem isn&amp;rsquo;t mitigated at all by growing data or log files. You can have the largest file allowed by General Purpose storage and you&amp;rsquo;ll still see IO freezes of 15-60 seconds happen regularly on them over time, just like the smallest files. You will see it when you&amp;rsquo;re so far under the IOPs and throughput thresholds that it&amp;rsquo;s laughable. &lt;em&gt;You will see it in a can, you will see it in a ham; You will see it while you troubleshoot with every trace and plan; File size won’t change a thing—it’s not the magic key; You’ll still get hit with storage freezes unpredictably.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But the fact that people know about the &amp;ldquo;weird file size problem&amp;rdquo; blocks them from understanding this. Folks regularly argue with me when I let them know that I&amp;rsquo;ve received confirmation from the Managed Instance product group that increasing file size will not mitigate or stop the storage stalls. They are &lt;em&gt;sure&lt;/em&gt; that if you grow the files it will make the issue better.&lt;/p&gt;
&lt;h2 id="when-the-workaround-becomes-misdirection"&gt;When the Workaround Becomes Misdirection&lt;/h2&gt;
&lt;p&gt;The workaround&amp;ndash; &amp;ldquo;grow the files! make &amp;rsquo;em huge! pay more for maybe better IOPS!&amp;rdquo; has become the performance placebo of Azure SQL support. It gives people &lt;em&gt;something&lt;/em&gt; to recommend. It creates the illusion of understanding.&lt;/p&gt;
&lt;p&gt;But the workaround creates tunnel vision. “&lt;strong&gt;THIS&lt;/strong&gt; is the performance problem. We’ve solved it. Move along.”&lt;/p&gt;
&lt;p&gt;Meanwhile, the nastier problem remains massively disruptive to users, and Microsoft support won&amp;rsquo;t even acknowledge it.&lt;/p&gt;
&lt;h2 id="cognitive-biases"&gt;Cognitive Biases&lt;/h2&gt;
&lt;p&gt;This all lines up with common cognitive biases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://en.wikipedia.org/wiki/Streetlight_effect"&gt;&lt;strong&gt;Streetlight Effect&lt;/strong&gt;&lt;/a&gt;: people keep poking at the file size thing because it’s the only issue illuminated by documentation and support scripts.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Law_of_the_instrument"&gt;&lt;strong&gt;Maslow’s Hammer&lt;/strong&gt;&lt;/a&gt;: once the workaround exists, suddenly every performance problem starts to look like it must be file-size related.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Normalcy_bias"&gt;&lt;strong&gt;Normalcy Bias&lt;/strong&gt;&lt;/a&gt;: hey, 60-second storage stalls &lt;em&gt;sound&lt;/em&gt; too extreme to be real, right?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And when you show someone new evidence, &lt;a href="https://en.wikipedia.org/wiki/Semmelweis_reflex"&gt;&lt;strong&gt;Semmelweis Reflex&lt;/strong&gt;&lt;/a&gt; kicks in—we reject new information out of habit, because it contradicts what we&amp;rsquo;ve been taught.&lt;/p&gt;
&lt;p&gt;In a complex world, it&amp;rsquo;s easy to fall into a feedback loop that feels logical in the moment, but keeps us stuck. Our brains prefer a known explanation to a messier reality.&lt;/p&gt;
&lt;h2 id="what-to-do-about-it"&gt;What to do About It?&lt;/h2&gt;
&lt;p&gt;First off, if you&amp;rsquo;re using Azure SQL General Purpose and you&amp;rsquo;re experiencing weird lockups, long-running queries that don’t make sense, or sessions waiting on I/O for disturbingly long periods—&lt;strong&gt;you’re not imagining things.&lt;/strong&gt; You can try growing your files, but it&amp;rsquo;s not going to fix the whole issue. And sorry, but Azure Support isn&amp;rsquo;t going to understand the issue unless you escalate about six levels, and then you&amp;rsquo;re going to be told to just wait for GPV2.&lt;/p&gt;
&lt;p&gt;More generally, we need to keep our minds open to new information.&lt;/p&gt;
&lt;p&gt;Ask the awkward questions. Use data to measure performance yourself, and break it down critically. When you find something that doesn&amp;rsquo;t line up with the documentation or the community folklore, go ahead and speak up.&lt;/p&gt;
&lt;p&gt;Our most valuable technical trait isn&amp;rsquo;t knowing database internals or mastering syntax. It’s being persistently curious enough to keep asking questions when the data doesn&amp;rsquo;t all line up.&lt;/p&gt;</description></item><item><title>100 Things I Hate About Views: Undeclared Data Types in Columns</title><link>https://kendralittle.com/2025/03/14/views-data-type-undeclared-int-sql-server/</link><pubDate>Fri, 14 Mar 2025 17:44:51 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/03/14/views-data-type-undeclared-int-sql-server/</guid><description>&lt;p&gt;Views let you do dumb things by accident in SQL Server. Then they make you have to think way too hard to fix them.&lt;/p&gt;
&lt;p&gt;Most of the time when people create views, they start by refining a &lt;code&gt;SELECT&lt;/code&gt; query, then turn it into a view. People also often create multiple views that pull different slices of data and UNION the results together.&lt;/p&gt;
&lt;p&gt;Combined, these two things easily lead to undeclared datatypes in views with problematic implicit conversions.&lt;/p&gt;
&lt;h2 id="sql-server-lets-you-define-a-view-with-columns-with-undeclared-data-types"&gt;SQL Server Lets You Define a View with Columns with Undeclared Data Types&lt;/h2&gt;
&lt;p&gt;You can even have it return a null if you&amp;rsquo;re going to UNION that view with other things.&lt;/p&gt;
&lt;p&gt;It doesn&amp;rsquo;t look very weird at all, it just looks like this&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i_am_view&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* column2,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; column3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; FROM dbo.Sometable, etc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="lets-say-we-have-that-view-plus-a-related-table"&gt;Let&amp;rsquo;s Say We have That View, Plus a Related Table&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the table and its rows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i_am_table&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i_am_table&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ONE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2024-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2025-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="select-from-the-view-and-union-with-the-table"&gt;Select from the View and Union with the Table&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the query&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i_am_view&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i_am_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_modified_date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-results-are-odd"&gt;The Results are Odd&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Notable bits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Row 1&lt;/strong&gt; came from the view. The last_modified_date column, which was also not given a data type in our query, returned January 1, 1900&amp;ndash; it got a magic default value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Row 4&lt;/strong&gt; has 0 as the value for some_column. This was an empty string in the table, but it&amp;rsquo;s been converted to a numeric 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-query-execution-plan-explains-more"&gt;The Query Execution Plan Explains More&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at that warning on the SELECT operator, plus that compute scalar operator after we read the table.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results_query_plan.png"&gt;
&lt;/figure&gt;
&lt;h2 id="were-warned-about-an-implicit-conversion"&gt;We&amp;rsquo;re Warned About an Implicit Conversion&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results_query_plan_warning_implicit_conversion.png"&gt;
&lt;/figure&gt;
&lt;p&gt;I find these messages really hard to read with the text all crammed together. Here it is with a lot of spacing added:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; Type conversion IN expression (
CONVERT_IMPLICIT
(integer,
[views].[dbo].[i_am_table].[some_column]
,0)
) may affect &amp;#34;CardinalityEstimate&amp;#34; IN query plan choice&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SQL Server decided that it needed to convert the &lt;code&gt;some_column&lt;/code&gt; values in &lt;code&gt;dbo.i_am_table&lt;/code&gt; from the datatype they are stored as&amp;ndash; &lt;code&gt;VARCHAR(100)&lt;/code&gt; &amp;ndash; into the &lt;code&gt;INT&lt;/code&gt; datatype.&lt;/p&gt;
&lt;p&gt;Looking at the compute_scalar operator confirms this.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results_query_plan_compute_scalar.png" width="600"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;Expr1005&lt;/code&gt; is defined as the result of that CONVERT_IMPLICIT function, which is converting values from &lt;code&gt;some_column&lt;/code&gt; to integers. &lt;code&gt;Expr1005&lt;/code&gt; is returned from this operator along with the last_modified_date column.&lt;/p&gt;
&lt;h2 id="if-we-remove-the-where-clause-the-query-fails"&gt;If We Remove the Where Clause, the Query Fails&lt;/h2&gt;
&lt;p&gt;If we let that row where &lt;code&gt;some_column&lt;/code&gt; has the value &amp;ldquo;one&amp;rdquo; through, the query fails with the error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 245, Level 16, State 1, Line 52
Conversion failed when converting the varchar value &amp;lsquo;ONE&amp;rsquo; to data type int.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results_query_plan_failed_query.png"&gt;
&lt;/figure&gt;
&lt;p&gt;I guess we can&amp;rsquo;t implicitly convert words to integers.&lt;/p&gt;
&lt;h2 id="why-an-integer"&gt;Why an Integer?&lt;/h2&gt;
&lt;p&gt;When we created the view, we defined it with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We didn&amp;rsquo;t give SQL Server anything to go on, so it guessed int.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results_sp_help.png"&gt;
&lt;/figure&gt;
&lt;p&gt;The same thing happens if we use this syntax to create a temp table.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/temp_table_undeclared_data_type_sp_help.png"&gt;
&lt;/figure&gt;
&lt;h2 id="we-shouldnt-leave-this-to-chance"&gt;We shouldn&amp;rsquo;t leave this to chance&lt;/h2&gt;
&lt;p&gt;I wish SQL Server wouldn&amp;rsquo;t let you create a view this way, but it does. However, we&amp;rsquo;re much better off specifying a data type, which we can do with the syntax:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i_am_view&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This avoids errors with data type conversions, not to mention unexpected results and performance issues with type conversions.&lt;/p&gt;</description></item><item><title>What the Decline of SQL Server Quality Means for Developers and DBAs</title><link>https://kendralittle.com/2025/03/10/what-the-decline-of-sql-server-quality-means-developers-dbas/</link><pubDate>Mon, 10 Mar 2025 08:55:51 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/03/10/what-the-decline-of-sql-server-quality-means-developers-dbas/</guid><description>&lt;p&gt;&amp;lsquo;Is it just me, or is SQL Server quality slipping?&amp;rsquo;&lt;/p&gt;
&lt;p&gt;I asked myself that question for couple/few years until I faced up to it: SQL Server is well into a period where Microsoft investment is waning, and Microsoft regularly isn&amp;rsquo;t able to deliver the features they promise.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/uhoh.png" width="260"&gt;
&lt;/figure&gt;
&lt;h2 id="feature-announcements--usable-features"&gt;&lt;strong&gt;Feature Announcements ≠ Usable Features&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Remember when folks waited for Service Pack 1 for SQL Server releases before trying a feature, because they weren&amp;rsquo;t sure about the quality?&lt;/p&gt;
&lt;p&gt;We don&amp;rsquo;t have service packs anymore, but these days a lot of features wouldn&amp;rsquo;t even be &lt;em&gt;available&lt;/em&gt; by Service Pack 3, much less Service Pack 1.&lt;/p&gt;
&lt;p&gt;We are in an era when Microsoft announces features for SQL Server that they don&amp;rsquo;t deliver for years&amp;ndash; or perhaps at all. For example, &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/query-store-for-secondary-replicas?view=sql-server-ver16"&gt;Query Store on readable secondaries&lt;/a&gt; was a SQL Server 2022 feature that we&amp;rsquo;ve still never seen in a production-ready state: it remains completely unavailable in Azure SQL offerings. It stays in a &amp;ldquo;preview&amp;rdquo; state that &amp;ldquo;is not intended for production deployments&amp;rdquo; in the boxed product years after the 2022 release.&lt;/p&gt;
&lt;p&gt;Similarly, we saw other flagship features of SQL Server 2022, like the ability to fail over to Azure SQL Managed Instances, take years to crawl out of preview.&lt;/p&gt;
&lt;h2 id="azure-sql-managed-instance-storage-that-freezes-for-60-seconds"&gt;&lt;strong&gt;Azure SQL Managed Instance: Storage That Freezes for 60 Seconds&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Azure SQL Managed Instance itself is one of the sharp indicators of a lack of Microsoft investment.&lt;/p&gt;
&lt;p&gt;The General Purpose tier of Azure SQL has an incredibly bad &lt;strong&gt;storage latency problem&lt;/strong&gt;&amp;ndash; storage &lt;a href="https://kendralittle.com/2024/12/18/azure-sql-managed-instance-storage-regularly-slow-60-seconds/"&gt;regularly stalls up to 60 seconds&lt;/a&gt; regardless of utilization or configuration patterns, and there&amp;rsquo;s nothing you can do as a user to prevent this.&lt;/p&gt;
&lt;p&gt;That’s essentially downtime, and accepting this as &amp;ldquo;normal&amp;rdquo; in a hosted database product is, well, bizarre. Yet Microsoft can&amp;rsquo;t get the newer version of the storage, GPV2, over the line and out of preview &lt;a href="https://techcommunity.microsoft.com/blog/azuresqlblog/introducing-azure-sql-managed-instance-next-gen-gp/4092647"&gt;after announcing it a year ago&lt;/a&gt;. &lt;em&gt;Note to Microsoft employees who think you can fix this by growing file sizes: you can&amp;rsquo;t. The fact that smaller files have worse IO performance is a completely separate bad thing about the product, users have to deal with both. Even the largest files will regularly see 60 second IO stalls.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="lingering-sql-server-bugs-are-piling-up-long-unfixed"&gt;&lt;strong&gt;Lingering SQL Server Bugs are Piling Up, Long Unfixed&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s more difficult than ever to get SQL Server bugs diagnosed and fixed.&lt;/p&gt;
&lt;p&gt;Take the &lt;strong&gt;query hash bug&lt;/strong&gt;—where SQL Server randomly replaces &lt;code&gt;query_hash&lt;/code&gt; values, making performance tuning nearly impossible &lt;a href="https://kendralittle.com/2024/11/24/query-hash-values-meaningless-same-as-query-plan-hash-sql-server/"&gt;(source)&lt;/a&gt;. This bug has been lurking for &lt;em&gt;years&lt;/em&gt; and impacts SQL Server 2008 through the latest versions.&lt;/p&gt;
&lt;p&gt;Similarly, &lt;a href="https://kendralittle.com/2024/02/21/queries-against-readable-availability-group-secondaries-may-fail-repeatedly-until-you-intervene/"&gt;SQL Server bugs with statistics with metadata errors that cause queries to fail on readable secondaries&lt;/a&gt; have been around since SQL Server 2012. There are a &lt;a href="https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/performance/memory-optimized-tempdb-out-of-memory"&gt;host of known problems with In-Memory Metadata for tempdb&lt;/a&gt;&amp;mdash; which maybe is why it remains completely unavailable for Azure SQL Database and Azure SQL Managed Instance, it&amp;rsquo;s hard to say. And &lt;a href="https://kendralittle.com/2024/02/07/sql-server-online-index-rebuild-offline-blocking-outage/"&gt;online index rebuilds aren&amp;rsquo;t always online&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And these are just the ones that I hit in a regular workday.&lt;/p&gt;
&lt;h2 id="all-microsoft-roads-lead-to-fabric"&gt;&lt;strong&gt;All Microsoft Roads Lead to Fabric&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Looking in from the outside, it seems clear that Microsoft’s focus has shifted: when it comes to data, the priority is Microsoft Fabric.&lt;/p&gt;
&lt;p&gt;Investment in data technologies are increasingly focused on the AI goldrush and quest to beat Databricks.&lt;/p&gt;
&lt;p&gt;It also feels like Microsoft has, at an organizational level, decided that SQL Server doesn&amp;rsquo;t need to evolve much more. When is the last time you heard of a SQL Server feature that felt groundbreaking and innovative to you? From my external viewpoint, it seems like Azure SQL Database Hyperscale tried to take on AWS Aurora, and after a crowd of users didn&amp;rsquo;t materialize then product innovation sharply dwindled.&lt;/p&gt;
&lt;h2 id="will-the-pendulum-swing-back"&gt;&lt;strong&gt;Will the Pendulum Swing Back?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Honestly, in this case, I&amp;rsquo;m not sure.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m quite positive that Microsoft will keep releasing new versions of SQL Server and keep selling licenses for quite a long time. The product has a large enough user base and enough functionality that it will keep making money for years, even if it goes onto a full mode of quiet life support with only small features added and bug fixes released.&lt;/p&gt;
&lt;p&gt;Will innovation and strong investment actually swing back to SQL Server, though? If this happens, I think it&amp;rsquo;s going to be a while.&lt;/p&gt;
&lt;h2 id="what-this-means-for-developers-and-dbas"&gt;&lt;strong&gt;What This Means for Developers and DBAS&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;So SQL Server is receiving limited investment: what does that mean to DBAs and Developers?&lt;/p&gt;
&lt;p&gt;It doesn&amp;rsquo;t necessarily mean work is less interesting for database folks&amp;ndash; I work with SQL Server databases every day, and I love my job. It remains fascinating and full of tough problems.&lt;/p&gt;
&lt;p&gt;But Microsoft&amp;rsquo;s declining level of investment in SQL Server will change things for those of us who use the product:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You may adjust your technical focus, depending on where you are in your career path&lt;/strong&gt;: For people earlier in their career cycle, this is a strong signal not to specialize only on SQL Server. If relational databases are your interest, work to get experience with multiple database platforms. Postgres is already common and will continue to grow its userbase.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Slowing upgrade trends&lt;/strong&gt;: Mirosoft is still planning on releasing SQL Server 2025 (without having finished SQL Server 2022, arguably). The will still push users to upgrade and limit the number of versions they support. However, the pattern of not delivering promised features and the slow rate of addressing bugs means that users will be slower to upgrade services to new major versions. This will, in turn, probably mean users are slower to report new bugs, and the cycle will deepend and become even more sluggish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&amp;rsquo;ll need to be a squeakier wheel&lt;/strong&gt;: The problem isn’t that no one at Microsoft cares about SQL Server—there are still engineers and product managers who genuinely want to improve it. The issue is that &lt;strong&gt;at a high leadership level, investment has shifted elsewhere&lt;/strong&gt;. If nobody complains and we all seem quite happy to just keep paying for upgrades, why would that ever change? Microsoft prioritizes what makes the most noise internally, and that noise comes from signals—support tickets, customer escalations (particularly to sales teams), and public feedback. If we want long-standing issues fixed and critical features delivered, we need to keep making noise and providing strong signals that product investment matters.&lt;/p&gt;</description></item><item><title>AI Will Eliminate DBA Jobs Faster Than You Think</title><link>https://kendralittle.com/2025/03/02/ai-will-eliminate-dba-jobs-faster-than-you-think/</link><pubDate>Sun, 02 Mar 2025 10:18:54 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/03/02/ai-will-eliminate-dba-jobs-faster-than-you-think/</guid><description>&lt;p&gt;I listened to &lt;a href="https://podcasts.apple.com/us/podcast/anthropics-c-e-o-dario-amodei-on-surviving-the-a-i-endgame/id1528594034?i=1000696782462"&gt;&amp;lsquo;Surviving the A.I. Endgame&amp;rsquo;&lt;/a&gt; this weekend and realized: I&amp;rsquo;ve become one of the believers that AI advances are very likely to completely change tech and knowledge roles as we know them over the next 10 years. This is going to dramatically shrink the workforce across MANY roles (and many of those impacted will be outside of the tech sector). It isn&amp;rsquo;t that people won&amp;rsquo;t be needed anymore, but &lt;em&gt;far fewer&lt;/em&gt; people will be needed. Including people with database administrator (DBA) roles like mine.&lt;/p&gt;
&lt;p&gt;Database administrators have been hearing that technological improvements will mean DBAs are no longer needed for 20+ years, though. So, as a DBA, why would I start believing this now?&lt;/p&gt;
&lt;!-- more --&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/ai-dba.png"
alt="Illustration of an AI-powered database administrator"&gt;
&lt;/figure&gt;
&lt;h2 id="im-not-an-ai-fanboy-im-not-an-ai-opponent"&gt;I&amp;rsquo;m Not an AI Fanboy. I&amp;rsquo;m Not an AI Opponent.&lt;/h2&gt;
&lt;p&gt;This post is about what I believe is &lt;em&gt;likely&lt;/em&gt; to happen&amp;ndash; not what I &lt;em&gt;want&lt;/em&gt; to happen. I&amp;rsquo;m not labeling this prediction as a &amp;ldquo;good&amp;rdquo; or &amp;ldquo;bad&amp;rdquo; outcome, either.&lt;/p&gt;
&lt;p&gt;This is what my experience has led me to believe is coming.&lt;/p&gt;
&lt;h2 id="ive-been-working-with-an-ai-agent"&gt;I&amp;rsquo;ve been Working with an AI Agent&lt;/h2&gt;
&lt;p&gt;Lately I&amp;rsquo;ve been writing a fair amount of Python with an AI agent. If you&amp;rsquo;ve mostly used AI chat experiences, I think the Agent experience is pretty different. Agents can do things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apply changes for you in multiple files, verify that they work, then let the user modify them, accept them, or reject them.&lt;/li&gt;
&lt;li&gt;Handle multiple complex steps &amp;ndash; like verifying how it is doing at a task, noticing problems in its approach, and adapting its approach&lt;/li&gt;
&lt;li&gt;Report on what it is doing, and take further input from the user while it is still working.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In many ways I feel like I can see the software team behind the agent do things as time goes on, because I feel like the agent is gradually getting better at learning when and how to identify its own mistakes before telling me it&amp;rsquo;s done with a task.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also noticed that there&amp;rsquo;s a learning curve for me: as I get better at providing the right context from files and sources for tasks, my results get better. As I get better in understanding how as a user I can shape the Agent&amp;rsquo;s behavior, I can give the Agent instructions that make it better at handling things it doesn&amp;rsquo;t start out being very good at.&lt;/p&gt;
&lt;p&gt;The agent dramatically increases my ability to get things done, to the point where it&amp;rsquo;s not too hard for me to see how &lt;em&gt;my&lt;/em&gt; role in the situation may rapidly become optional, then unnecessary.&lt;/p&gt;
&lt;h2 id="reflections-on-responding-to-database-performance-incidents"&gt;Reflections on Responding to Database Performance Incidents&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Happy databases are all alike; every unhappy database is unhappy in its own way.&amp;rdquo; &lt;a href="https://en.wikipedia.org/wiki/Anna_Karenina_principle"&gt;Anna Karenina principle&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While there are plenty of bizarre bottlenecks and performance situations that one can find with databases, responding to database performance incidents generally involves doing a set of very similar tasks to collect information, diagnose what is going on, and suggest next steps and mitigations. There is a fairly short list of &amp;ldquo;frequent fliers&amp;rdquo; that are very commonly causes of bad performance that one can check for as part of this process, and verify them or rule them out.&lt;/p&gt;
&lt;p&gt;This set of tasks and diagnostic rules are fairly complex. I&amp;rsquo;ve had plenty of success in teaching other people these tasks and rules, but up to this point I didn&amp;rsquo;t think that this could be automated.&lt;/p&gt;
&lt;p&gt;After my recent experience working with an Agent I don&amp;rsquo;t think it&amp;rsquo;s gonna be long before we get there, though.&lt;/p&gt;
&lt;h2 id="an-ai-agent-doesnt-have-to-be-perfect-just-make-fewer-mistakes-than-a-person"&gt;An AI Agent Doesn&amp;rsquo;t have to be Perfect&amp;ndash; Just Make Fewer Mistakes Than a Person&lt;/h2&gt;
&lt;p&gt;DBA jobs won&amp;rsquo;t be the first to be replaced by AI agents because of the risk associated with data loss. However, I think the quality of AI Agents will become high enough that it starts to make sense.&lt;/p&gt;
&lt;p&gt;Agent quality isn&amp;rsquo;t the only factor, however. Cost is also a factor in the algorithm. AI agents can be expensive, but so are human employees.&lt;/p&gt;
&lt;h2 id="but-kendra-ai-is-bad-at-sql"&gt;But Kendra, AI is Bad at SQL&lt;/h2&gt;
&lt;p&gt;Oh, I agree, I have plenty of examples of LLMs spewing utter nonsense and writing garbage SQL.&lt;/p&gt;
&lt;p&gt;My views are largely informed by my experience using an AI Agent to get DBA projects done that require lots of automation. I&amp;rsquo;ve certainly generated SQL scripts in the course of this, but they&amp;rsquo;ve been fairly simple and related to working with metadata. The AI Agent is already pretty excellent at all of this stuff.&lt;/p&gt;
&lt;p&gt;My belief is that the tooling will continue to improve rapidly and that this will cross into other areas. I think different languages/work areas will have agents that are tuned for those areas. I think it will get good at even complex SQL. And I think this evolution is going to continue to be quite rapid.&lt;/p&gt;
&lt;h2 id="whats-a-dba-to-do"&gt;What&amp;rsquo;s a DBA to Do?&lt;/h2&gt;
&lt;p&gt;Depends on your personality, really. If you&amp;rsquo;re a startup-y type, there&amp;rsquo;s probably decent money to be made with jumping on the AI Agent Tooling Building Bandwagon.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not a startup-y type, there&amp;rsquo;s plenty of time to gather more data and see if my little 10 year prediction here is totally bonkers or not.&lt;/p&gt;</description></item><item><title>How to Stop SSDT / Database Projects / SQLPackage from Modifying Database Options</title><link>https://kendralittle.com/2025/02/13/sqlpackage-how-to-stop-deploy-changing-database-options/</link><pubDate>Thu, 13 Feb 2025 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2025/02/13/sqlpackage-how-to-stop-deploy-changing-database-options/</guid><description>&lt;p&gt;SQL Server&amp;rsquo;s free state-based version control tooling was introduced under the &amp;lsquo;Data Dude&amp;rsquo; brand, then became known as &amp;lsquo;SQL Server Data Tools&amp;rsquo; (SSDT). Its extension for the (now dying) Azure Data Studio IDE is called &amp;lsquo;SQL Database Projects&amp;rsquo;. If you need to find documentation, you often need to know to search for &lt;a href="https://learn.microsoft.com/en-us/sql/tools/sqlpackage/sqlpackage"&gt;specific component names like SQLPackage.exe&lt;/a&gt;, which is a command line utility used to deploy SSDT Projects AKA SQL Database Projects.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="database-projects-control-more-than-objects-inside-the-database"&gt;Database Projects Control More Than Objects Inside the Database&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQLPackage.png" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;By default, deploying a SQL Database Project with SQLPackage.exe doesn&amp;rsquo;t only deploy the schema of the tables, procedures, and functions in the project. It will also deploy select attributes of SQL Server databases themselves, things like page verification settings, whether snapshot isolation is enabled, and some Query Store settings.&lt;/p&gt;
&lt;p&gt;If there&amp;rsquo;s a complete list of the database properties that are version controlled with SQL Database Projects, I haven&amp;rsquo;t found it. &lt;em&gt;Update: after publication of this post, &lt;a href="https://learn.microsoft.com/en-us/sql/tools/sql-database-projects/concepts/project-properties"&gt;a doc appeared&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="sometimes-you-dont-want-to-overwrite-database-properties-on-your-target-databases"&gt;Sometimes You Don&amp;rsquo;t Want to Overwrite Database Properties on Your Target Databases&lt;/h2&gt;
&lt;p&gt;For various reasons, you may not always want your project to deploy database settings everywhere. Perhaps you deploy your project to many single-tenant databases and you are gradually rolling out changes to settings across your environment, for example.&lt;/p&gt;
&lt;p&gt;In this case, I&amp;rsquo;ve found that running SQLPackage.exe with the &lt;code&gt;/p:ScriptDatabaseOptions=False&lt;/code&gt; parameter seems to work: when this is set, sqlpackage.exe won&amp;rsquo;t overwrite database properties that are controlled by the database project but vary from their definition in source.&lt;/p&gt;
&lt;h2 id="avoid-excludeobjecttypes-for-this"&gt;Avoid ExcludeObjectType(s) for This&lt;/h2&gt;
&lt;p&gt;But beware: there are &lt;a href="https://learn.microsoft.com/en-us/sql/tools/sqlpackage/sqlpackage-publish"&gt;some other documented options like &lt;code&gt;/p:ExcludeObjectType:&amp;quot;DatabaseOptions&amp;quot;&lt;/code&gt; which do NOT work for this&lt;/a&gt;. I haven&amp;rsquo;t been able to identify if setting that property, or using the similar &lt;code&gt;ExcludeObjectTypes&lt;/code&gt;, has any effect at all, or why those exist. I tested those for a good hour, trying to get them to work and despairing until I found that &lt;code&gt;/p:ScriptDatabaseOptions=False&lt;/code&gt; does the trick.&lt;/p&gt;</description></item><item><title>Buyer Beware: Azure SQL Managed Instance Storage Is Regularly as Slow as 60 Seconds</title><link>https://kendralittle.com/2024/12/18/azure-sql-managed-instance-storage-regularly-slow-60-seconds/</link><pubDate>Wed, 18 Dec 2024 09:26:20 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/12/18/azure-sql-managed-instance-storage-regularly-slow-60-seconds/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: Microsoft has announced the general availability of the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;Next-gen General Purpose service tier&lt;/a&gt; for Azure SQL Managed Instance, which includes improvements to I/O latency, IOPS, and transaction log throughput. This post describes the original General Purpose blob storage. You don't want that.
&lt;/div&gt;
&lt;p&gt;What are your stories of unbelievably bad performance from cloud vendors? I&amp;rsquo;ll go first. For years, Azure SQL Managed Instance&amp;rsquo;s General Purpose Tier has &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits?view=azuresql"&gt;documented &amp;lsquo;approximate&amp;rsquo; storage latency as being &amp;ldquo;5-10 ms.&amp;rdquo;&lt;/a&gt; This week they added a footnote: &amp;ldquo;This is an average range. Although the vast majority of IO request durations will fall under the top of the range, outliers which exceed the range are possible.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;How approximate is that 5-10 milliseconds, you might wonder? If you use Azure SQL Managed Instance these days, you will regularly find messages in your SQL Server Error log indicating that all data and log files have experienced latency of up to &lt;strong&gt;60 seconds&lt;/strong&gt;. At least, 60 seconds is the maximum I&amp;rsquo;ve observed personally, looking in the logs of several customers&amp;rsquo; Managed Instances. Could it be worse? Microsoft hasn&amp;rsquo;t documented a ceiling. My testing shows that this latency occurs randomly to your workload and is not related to your resource usage: using less IO will not make the errors less likely. You have no way to avoid these storage failures (I don&amp;rsquo;t see how 15-60 second latency is not a failure), and they can occur &lt;strong&gt;anytime&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a mathematician here, but one minute appears to be &lt;em&gt;6000x higher than that advertised 10ms latency&lt;/em&gt;. Is that what a prospective customer would assume when reading the documentation? And when it comes to a hosted database service, is that an acceptable product feature?&lt;/p&gt;
&lt;!-- more --&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fax.png"
alt="Illustration of a fax machine" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="a-note-for-all-the-microsoft-employees-who-think-this-is-about-file-sizes"&gt;A Note for All the Microsoft Employees Who Think This is About File Sizes&lt;/h2&gt;
&lt;p&gt;I keep getting comments in various places from Microsoft employees who think I&amp;rsquo;m missing something obvious, so let me say up front here: this issue is NOT mitigated by growing database file sizes.&lt;/p&gt;
&lt;p&gt;Yes, the storage in Microsoft&amp;rsquo;s offerings in Azure is &lt;em&gt;so&lt;/em&gt; bad that you have to grow file sizes to different levels to make your general IO performance slightly less terrible.&lt;/p&gt;
&lt;p&gt;However, the issue I&amp;rsquo;m talking about here, where storage will stop responding for your data and log files for up to 60 seconds, will happen regardless of the size of those files. You can grow them all you want, you&amp;rsquo;ll still regularly see stalls of 45-60 seconds. It &lt;strong&gt;is&lt;/strong&gt; that bad.&lt;/p&gt;
&lt;h2 id="what-are-reasonable-latencies-for-database-storage"&gt;What are Reasonable Latencies for Database Storage?&lt;/h2&gt;
&lt;p&gt;Back in 2013, &lt;a href="https://www.sqlskills.com/blogs/paul/are-io-latencies-killing-your-performance/"&gt;Paul Randal, who was once a PM on the Storage Engine team at Microsoft, wrote&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Everyone has their idea of what constitutes good or bad I/O latency, and here’s my take:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Excellent: &amp;lt; 1ms&lt;/li&gt;
&lt;li&gt;Very good: &amp;lt; 5ms&lt;/li&gt;
&lt;li&gt;Good: 5 – 10ms&lt;/li&gt;
&lt;li&gt;Poor: 10 – 20ms&lt;/li&gt;
&lt;li&gt;Bad: 20 – 100ms&lt;/li&gt;
&lt;li&gt;Shockingly bad: 100 – 500ms&lt;/li&gt;
&lt;li&gt;WOW!: &amp;gt; 500ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Paul is talking about average latencies. So let&amp;rsquo;s think about what average latency ends up looking like in a 5 minute window when you have a 45 or 60 &lt;strong&gt;second&lt;/strong&gt; IO stall on all of the read/write requests to your data and log files. I don&amp;rsquo;t want to put words in Paul&amp;rsquo;s mouth, but I think we&amp;rsquo;re in &amp;ldquo;what the hell is wrong with this?&amp;rdquo; territory by his scale.&lt;/p&gt;
&lt;h2 id="general-purpose---more-like-no-purpose"&gt;General Purpose - More Like No Purpose&lt;/h2&gt;
&lt;p&gt;Microsoft SQL Server, the product, agrees that multiple seconds of stalled IO are an alarming problem and should be considered a serious error for the storage subsystem. Back in 2010, Microsoft&amp;rsquo;s Bob Dorr shared his excellent &lt;a href="https://techcommunity.microsoft.com/blog/sqlserversupport/how-it-works-bob-dorrs-sql-server-io-presentation/316031"&gt;SQL Server I/O Presentation&lt;/a&gt;. In it, he wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Stalled/Stuck I/O: SQL Server 2000 SP4 added a warning that the I/O was taking too long and appears to be stuck or stalled. When an I/O request is posted (async) the time is kept (sys.dm_io_pending_io_requests) with the tracking information. Lazy writer checks these lists periodically and if any I/O is still pending at the operating system level (FALSE == HasOverlappedIoCompleted) and 15 seconds has elapsed the warning is recorded. Each file will report the number of stalls at most every 5 minutes to avoid flooding the log.&lt;/p&gt;
&lt;p&gt;Since a normal I/O request should respond in ~15ms or less 15 seconds is way too long. For example if the I/O request is stalled for 30 seconds and the query timeout is 30 seconds it can cause query timeouts. If the stalled I/O request if for the log it can cause unwanted blocking situations.&lt;/p&gt;
&lt;p&gt;If you are seeing these warnings you need to double check the I/O sub-system and use SQLIOSIM.exe to help narrow the problem. It can be anything from the configured HBA queue depth, multi-path failover detection mechanism, virus scanners or other filter drivers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But these days, dear reader, it could simply be that you are using Microsoft&amp;rsquo;s Azure SQL offering. You will not be able to take action on any of those things.&lt;/p&gt;
&lt;p&gt;Bob Dorr&amp;rsquo;s warnings are worth reiterating here: stalled/stuck I/O will regularly cause blocking in SQL Server. The longer the duration of the stall, the more blocking can pile up, and this can push the impacts of that storage latency on your workload to &lt;strong&gt;far longer than 60 seconds&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="how-much-does-general-purpose-cost-again"&gt;How Much does General Purpose Cost Again?&lt;/h2&gt;
&lt;p&gt;Here are some sample prices for pay-as-you-go in US-East today:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;24 vCore, Premium Series Memory Optimized - 16 TB storage - $7,547.47/month - &lt;em&gt;$90,569.64/year&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;64 vCore, Premium Series Memory Optimized - 16 TB storage - $16,412.74/month - &lt;em&gt;$196,952.88/year&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can spend a lot on something where the storage is regularly slower than a fax machine.&lt;/p&gt;
&lt;h2 id="its-simple-to-find-these-errors-heres-how"&gt;It&amp;rsquo;s Simple to Find These Errors. Here&amp;rsquo;s How.&lt;/h2&gt;
&lt;p&gt;To find these errors, simply open the SQL Server log and search for &amp;ldquo;longer than 15 seconds.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll find messages that look like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SQL Server has encountered [#] occurrence(s) of I/O requests taking longer than 15 seconds to complete on file [blah blah blah] in database [blah].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The end of the message will report the current highest latency IO, which I&amp;rsquo;ve seen be as high as 60 seconds on Azure SQL Managed Instance. I&amp;rsquo;m curious if you ever see it go higher&amp;ndash; please let me know in the comments.&lt;/p&gt;
&lt;p&gt;Some tips:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s incredibly slow to open the logs in Azure SQL Managed Instance, so I recommend using &lt;a href="https://erikdarling.com/sp_loghunter/"&gt;Erik Darling&amp;rsquo;s free sp_loghunter utility to find these programmatically&lt;/a&gt;. This also allows you to copy /paste the message info out.&lt;/li&gt;
&lt;li&gt;Azure SQL Managed Instance General Purpose deletes log files after it restarts (ugh), so you may not see the messages shortly after maintenance has occurred. This doesn&amp;rsquo;t mean the errors haven&amp;rsquo;t occurred recently, it just means the evidence has been lost. My experience has been that these messages regularly occur, both on read/write instances and failover partners, in different regions.&lt;/li&gt;
&lt;li&gt;As mentioned in Bob Dorr&amp;rsquo;s quote above, you will only see these errors logged every 5 minutes. They will occur for longer than that! You are only seeing a glimpse of the full scope of this problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-about-gpv2-why-is-general-purpose-still-gpv1-heres-the-gossip"&gt;What About Gpv2? Why is General Purpose Still Gpv1? Here&amp;rsquo;s the Gossip.&lt;/h2&gt;
&lt;p&gt;These errors occur on the only fully supported version of Managed Instance General Purpose, which Microsoft is now calling GPV1. A new version, GPV2, is in public preview. Microsoft may suggest you use this, but be sure to ask about the fine print. Ask them if there is an outage on GPV2, will Microsoft provide credits for that outage?&lt;/p&gt;
&lt;p&gt;This is why everyone is still using GPV1, because it&amp;rsquo;s fully supported. Preview products are not.&lt;/p&gt;
&lt;p&gt;But GPV2 has been in preview for a long time. With these massive problems of latency in GPV1, why hasn&amp;rsquo;t Microsoft simply made GPV2 fully supported?&lt;/p&gt;
&lt;p&gt;I have no secret or non-secret info here: Microsoft hasn&amp;rsquo;t told me this. And let&amp;rsquo;s face it, due to a long stream of my complaints and failed attempts to get Microsoft to either fix this storage problem or be transparent about it with their customers, I don&amp;rsquo;t think Microsoft will be telling me any secrets in the future.&lt;/p&gt;
&lt;p&gt;But I can tell you what rumors are going around in the community. These may or may not be true, but they do reflect the reality of what non-Microsoft DBAs and consultants in this space &lt;em&gt;think&lt;/em&gt; is the case about why GPV2 hasn&amp;rsquo;t shipped:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It will destroy the Business Critical offering. For a good while, rumors were that GPV2 was moving so slowly because having better storage in General Purpose would make the more expensive Business Critical offering even less attractive. Personally, I&amp;rsquo;ve found that &lt;a href="https://kendralittle.com/2024/01/29/is-azure-sql-managed-instance-business-critical-service-tier-worth-the-cost/"&gt;Business Critical Managed Instance already isn&amp;rsquo;t worth the price tag&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Internal wheelings and dealings have the Managed Instance product locked in to pay for General Purpose V1 storage for a long time, and they don&amp;rsquo;t want to take the financial loss of moving off it soon.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically, the community of folks who work with these products outside Microsoft think that GPV2 would work well, but internal politics and pricing and packaging issues keep customers stuck with a product with regular issues with abysmally bad storage performance, with the only alterative being to pay through the nose for Business Critical.&lt;/p&gt;
&lt;p&gt;These rumors may or may not be accurate, but they reflect the depression of the profressional community around the Azure SQL offering.&lt;/p&gt;
&lt;h2 id="does-azure-sql-database-also-have-regular-storage-latency-of-up-to-a-minute"&gt;Does Azure SQL Database Also have Regular Storage Latency of Up to a Minute?&lt;/h2&gt;
&lt;p&gt;As far as I&amp;rsquo;m aware, Azure SQL Database General Purpose uses the same storage model and will have the exact same issues. Probably the Fabric version is the same.&lt;/p&gt;
&lt;p&gt;Unfortunately for users, Azure SQL Database does not provide access to the SQL Server Error Log and does not provide ways to access all the errors in the log. It only provides very limited access into security errors.&lt;/p&gt;
&lt;p&gt;This probably means that latencies of up to 60 seconds can also occur on General Purpose Azure SQL Databases, but you&amp;rsquo;ll have a much harder time proving it.&lt;/p&gt;
&lt;h2 id="unreasonable-customers"&gt;Unreasonable Customers&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve professionally been a champion of Microsoft SQL Server for nearly 20 years. I&amp;rsquo;ve been proud of the product as it&amp;rsquo;s grown and worked to help developers and DBAs around the world get the most out of it. I&amp;rsquo;ve thought for a long time that it&amp;rsquo;s worth the money.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t believe that regular storage stalls of 15-60 seconds are acceptable for a hosted database product, though. And I also feel strongly that cloud vendors should be up front with customers about expected latencies with their products if they aren&amp;rsquo;t going to fix them.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been trying to be a good partner and let Microsoft document this issue before I share my technical observations here publicly. Yesterday, a friend asked if I&amp;rsquo;d seen the documentation pull request to update the resource limits page. The PR includes the comment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Added clarification to the IO latency duration range to make clearer that IO requests exceeding the range are possible. (Although not as clear as I&amp;rsquo;d like - using &amp;ldquo;compromise language&amp;rdquo; based on comment from &lt;em&gt;Microsoft Employee&amp;ndash;name redacted&lt;/em&gt; intended to balance clarity with keeping us out of trouble with unreasonable customers).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;m not linking to the PR because I don&amp;rsquo;t think it matters who wrote this. I also don&amp;rsquo;t particularly care if I&amp;rsquo;m the &amp;ldquo;unreasonable customer&amp;rdquo; here &amp;ndash; if thinking regular storage latency between 15 and 60 seconds is ludicrous and should not be kept secret is unreasonable, yeah, I&amp;rsquo;m REALLY unreasonable. You betcha.&lt;/p&gt;
&lt;p&gt;What I think is notable here is the blatant butt-covering. The focus isn&amp;rsquo;t on what&amp;rsquo;s best for the customer. The focus is on protecting the corporation FROM customer expectations. We might demand that products work as they are described.&lt;/p&gt;
&lt;p&gt;Y&amp;rsquo;all, if you&amp;rsquo;re a customer, check your error logs. Be willing to be called unreasonable for asking for something to live up to SQL Server 2000&amp;rsquo;s standards. Because customers are going to have to force Microsoft to make their hosted versions of SQL Server lived up to the product&amp;rsquo;s own expectations from SQL Server 2000. Complain to your Microsoft sales reps and cloud architects, and let them know this matters.&lt;/p&gt;
&lt;h2 id="sometimes-users-need-to-complain-before-changes-are-made"&gt;Sometimes Users Need to Complain Before Changes are Made&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t the first time it&amp;rsquo;s taken someone being brutally honest to change something at Microsoft &amp;ndash; it was only after Brent Ozar wrote &lt;a href="https://www.brentozar.com/archive/2013/07/sql-server-2014-standard-edition-sucks-and-its-all-your-fault/"&gt;SQL Server 2014 Standard Edition Sucks, and It’s All Your Fault&lt;/a&gt; that Microsoft raised the ridiculously low memory limit on Standard Edition from 64GB to 128GB. And I recall that some Microsoft employees were super mad that he dared to write that post at the time.&lt;/p&gt;
&lt;p&gt;Please, join me in complaining&amp;ndash; perhaps Microsoft can work through whatever internal political blockades exist and push GPV2 into full support. Maybe we &lt;strong&gt;can&lt;/strong&gt; make Azure SQL less of a cautionary tale. From my experience in working in software companies in general, I absolutely believe that customer complaints can be a real asset to the folks inside the corporation who &lt;strong&gt;do&lt;/strong&gt; care about customer experience and making things better. These complaints help them justify getting the resources to make changes. That is something that everything not labeled &amp;ldquo;Fabric&amp;rdquo; badly needs.&lt;/p&gt;
&lt;h2 id="what-are-your-cloud-stories-how-bad-does-it-get"&gt;What are Your Cloud Stories? How Bad does It Get?&lt;/h2&gt;
&lt;p&gt;Like I said at the beginning: I want to hear your stories. Azure, AWS, Google Cloud, whatever the Oracle Cloud is&amp;ndash; do you have a story of cloud performance that&amp;rsquo;s shockingly slow? I know I&amp;rsquo;m not alone here, I&amp;rsquo;d love to hear it.&lt;/p&gt;</description></item><item><title>Query Hash Values Are Meaningless in SQL Server: They May Be Reset to Be the Same Value as the Query Plan Hash</title><link>https://kendralittle.com/2024/11/24/query-hash-values-meaningless-same-as-query-plan-hash-sql-server/</link><pubDate>Sun, 24 Nov 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/11/24/query-hash-values-meaningless-same-as-query-plan-hash-sql-server/</guid><description>&lt;p&gt;This is the worst bug I&amp;rsquo;ve found in SQL Server to date. Previously, my top find was &lt;a href="https://kendralittle.com/2024/02/07/sql-server-online-index-rebuild-offline-blocking-outage/"&gt;SQL Server Online Index Rebuild sometimes happens offline without warning&lt;/a&gt;. This one has taken top slot because it makes my life more difficult on a daily basis.&lt;/p&gt;
&lt;p&gt;Background: SQL Server generates a &lt;code&gt;query_hash&lt;/code&gt; for each query. This is stored in &lt;code&gt;sys.query_store_query&lt;/code&gt; and it&amp;rsquo;s one of the primary ways you can identify what a query is across different Query Stores, or even the same Query Store over time, as surrogate &lt;code&gt;query_id&lt;/code&gt; values get reset if Query Store is cleared or data ages on. The &lt;code&gt;query_hash&lt;/code&gt; is a &amp;lsquo;Zobrist hash over the shape of the individual query, based on the bound (input) logical query tree. Query hints aren&amp;rsquo;t included as part of the hash.&amp;rsquo; (&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-store-query-transact-sql"&gt;Source&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Except that&amp;rsquo;s wrong. These days it&amp;rsquo;s &lt;strong&gt;NOT&lt;/strong&gt; always a hash of the query. If you force query plans, or if you use something like Automatic Plan Correction which forces plans, frequently the &lt;code&gt;query_hash&lt;/code&gt; value will be bizarrely overwritten by a &lt;code&gt;query_plan_hash&lt;/code&gt; value. So sometimes the &lt;code&gt;query_hash&lt;/code&gt; ends up being the &amp;lsquo;MD5 hash of the individual plan.&amp;quot; (&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-store-plan-transact-sql"&gt;Source&lt;/a&gt;) This occurs first in the query_plan XML, then it weirdly invades the Dynamic Management Views in Query Store for all &lt;code&gt;query_hash&lt;/code&gt; values for that &lt;code&gt;query_id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This presents a big challenge identifying queries in Query Store, or writing reliable diagnotic tooling and automation. I&amp;rsquo;ve reported this, but Microsoft hasn&amp;rsquo;t acknowledged that it&amp;rsquo;s a bug yet. At this point they are still asking me if there&amp;rsquo;s a pattern in how my TSQL is written that causes the &lt;code&gt;query_hash&lt;/code&gt; value to be the same as the &lt;code&gt;query_plan_hash&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Dear reader, if my TSQL was that powerful I would be doing MUCH wilder things than stunts with &lt;code&gt;query_hash&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;This post shows a repro of the problem and just how unreliable the &lt;code&gt;query_hash&lt;/code&gt; has become in SQL Server 2022 and Azure SQL Managed Instance. It may happen in additional versions, I haven&amp;rsquo;t tested more broadly than this.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/whered-my-query-hash-go.png"
alt="Illustration showing confusion about missing query hash values" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="set-up-our-environment-to-reproduce-this"&gt;Set Up Our Environment to Reproduce This&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using a copy of the StackOverflow2013 database to reproduce this. I&amp;rsquo;m currently running Developer Edition with &lt;code&gt;@@version&lt;/code&gt; Microsoft SQL Server 2022 (RTM-CU15-GDR) (KB5046862) - 16.0.4155.4 (X64).&lt;/p&gt;
&lt;p&gt;To get started, I reset basic configuration, make sure Query Store is enabled, clear Query Store, set database compat level to 160, and make sure Automatic Plan Correction is off.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Warning: Automatic Plan Correction automatically forces query plans and it causes this bug to spread rapidly. Especially avoid on relying on &lt;code&gt;query_hash&lt;/code&gt; to identify queries if you have that feature enabled. However, the bug occurs with plan forcing even if you&amp;rsquo;re manually forcing plans, so I&amp;rsquo;m reproducing that in this post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;show advanced options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MAX degree of parallelism&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cost threshold for parallelism&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OPERATION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;READ_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_STORAGE_SIZE_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEANUP_POLICY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;STALE_QUERY_THRESHOLD_DAYS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StackOverflow2013&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEAR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTOMATIC_TUNING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FORCE_LAST_GOOD_PLAN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="create-indexes-and-procedure-for-a-parameter-sniffing-situation"&gt;Create Indexes and Procedure for a Parameter Sniffing Situation&lt;/h2&gt;
&lt;p&gt;Next, I create two indexes and a stored procedure. This is not meant to be beautiful code, it&amp;rsquo;s code I wrote for a demo on &lt;a href="https://kendralittle.com/2024/01/17/automatic-plan-forcing-could-be-great-but-isnt-sql-server/"&gt;problems that can arise because Automatic Plan Correction doesn&amp;rsquo;t exclude temp tables&lt;/a&gt;, but it works to reproduce this issue as well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DropIndexes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Posts_OwnerUserId_INCLUDES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_Users_DisplayName_INCLUDES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsForDisplayname&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XACT_ABORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* This query selects FROM the #users temp TABLE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; That means it can USE statistics ON the temp TABLE to recompile IF the TABLE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; has a lot more data IN it than IN the cached plan */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="run-the-procedure-and-get-two-plans-in-cache-for-the-second-query"&gt;Run the Procedure and Get Two Plans in Cache for the Second Query&lt;/h2&gt;
&lt;p&gt;We run the following SQL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsForDisplayname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Clothilde&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsForDisplayname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Jon&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are no posts by users named &amp;lsquo;Clothilde%&amp;rsquo;, but there are a LOT of posts by users named &amp;lsquo;Jon%&amp;rsquo;, so a recompile naturally occurs due to statistics on the temporary table.&lt;/p&gt;
&lt;p&gt;Run the following query to review the hashes from both the Query Store DMVs and extract the same values from the query plan XML:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_hash_from_sys_query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan_hash_from_sys_query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_hash_extracted_from_plan_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DECLARE namespace sp=&amp;#34;http://schemas.microsoft.com/sqlserver/2004/07/showplan&amp;#34;; (/sp:ShowPlanXML/sp:BatchSequence/sp:Batch/sp:Statements/sp:StmtSimple/@QueryHash)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;varchar(64)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan_hash_extracted_from_plan_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DECLARE namespace sp=&amp;#34;http://schemas.microsoft.com/sqlserver/2004/07/showplan&amp;#34;; (/sp:ShowPlanXML/sp:BatchSequence/sp:Batch/sp:Statements/sp:StmtSimple/@QueryPlanHash)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;varchar(64)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_use_plan_extracted_from_plan_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DECLARE namespace sp=&amp;#34;http://schemas.microsoft.com/sqlserver/2004/07/showplan&amp;#34;; (/sp:ShowPlanXML/sp:BatchSequence/sp:Batch/sp:Statements/sp:StmtSimple/sp:QueryPlan/@UsePlan)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.PostsForDisplayname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class="blog-image"&gt;&lt;img src="https://kendralittle.com/images/query_store_query_hashes-looking_normal.png"
alt="Screenshot of Query Store showing query hashes that appear normal"&gt;
&lt;/figure&gt;
&lt;p&gt;We care about the second query in the procedure here, which has been assigned query_id 7. Query_id 7 has two different query plans, which have plan_ids 9 and 10. Here are the hash values we currently have (extracted from the image):&lt;/p&gt;
&lt;table class="blog-table" id="table_query_hash_all_messed_up"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Query Id&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Plan Id&lt;/th&gt;
&lt;th&gt;Query Hash sys.query_store_query&lt;/th&gt;
&lt;th&gt;Query Plan Hash sys.query_store_plan&lt;/th&gt;
&lt;th&gt;Query Hash in Plan XML&lt;/th&gt;
&lt;th&gt;Query Plan Hash in Plan XML&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x44A186BFC52AA053&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x44A186BFC52AA053&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x56049465CF9FFB95&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x56049465CF9FFB95&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This all looks normal and good:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query_id 7 has a &lt;code&gt;query_hash&lt;/code&gt; that is the same in &lt;code&gt;sys.query_store_query&lt;/code&gt; as it is in the query plans.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;query_plan_hash&lt;/code&gt; is a different value because it&amp;rsquo;s a hash of the query execution plan, not the query.&lt;/li&gt;
&lt;li&gt;The query_hash values in &lt;code&gt;sys.query_store_plan&lt;/code&gt; match the values in the query plan XML.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="force-a-query-plan-then-rerun-the-stored-procedure-for-a-new-value"&gt;Force a Query Plan, Then Rerun the Stored Procedure for a New Value&lt;/h2&gt;
&lt;p&gt;Next, we&amp;rsquo;re going to force the &amp;ldquo;small&amp;rdquo; query plan for this&amp;ndash; the one we ran for &lt;code&gt;Clothilde&lt;/code&gt; which had very few rows in the temp table.&lt;/p&gt;
&lt;p&gt;After forcing that plan, we run the procedure for the value &lt;code&gt;J&lt;/code&gt;, which is going to use that forced plan but will find a whole lotta rows. Run that twice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsForDisplayname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;J&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="somethings-gone-weird-in-the-query_hash-value-in-our-execution-plan"&gt;Something&amp;rsquo;s Gone Weird in the Query_hash Value in Our Execution Plan&lt;/h2&gt;
&lt;p&gt;Rerun the query above retrieving the &lt;code&gt;query_hash&lt;/code&gt; and &lt;code&gt;query_plan_hash&lt;/code&gt; values from the DMVs and the query plans.&lt;/p&gt;
&lt;p&gt;We have a new query plan, and something is starting to look weird:&lt;/p&gt;
&lt;figure class="blog-image"&gt;&lt;img src="https://kendralittle.com/images/query_store_query_hash-identical_to_query_plan_hash-dmv-view.png"
alt="Screenshot of Query Store DMV view showing query hash identical to query plan hash"&gt;
&lt;/figure&gt;
&lt;p&gt;Here are the values for query_id 7 extracted from the image:&lt;/p&gt;
&lt;table class="blog-table" id="table_query_hash_all_messed_up"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Query Id&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Plan Id&lt;/th&gt;
&lt;th&gt;Query Hash sys.query_store_query&lt;/th&gt;
&lt;th&gt;Query Plan Hash sys.query_store_plan&lt;/th&gt;
&lt;th&gt;Query Hash in Plan XML&lt;/th&gt;
&lt;th&gt;Query Plan Hash in Plan XML&lt;/th&gt;
&lt;th&gt;Is Use Plan Hint in Plan?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x44A186BFC52AA053&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x44A186BFC52AA053&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x56049465CF9FFB95&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x56049465CF9FFB95&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x61807D991A7B6914&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;SQL Server saw that we had forced a Query Plan. It also recognized that the row estimates in the forced query plan were way lower than the estimates for the currently executing query, so it created a &lt;a href="https://kendralittle.com/2018/03/12/what-is-a-morally-equivalent-execution-plan-and-why-is-it-good/"&gt;morally equivalent plan&lt;/a&gt; which has the same shape as the forced plan, but larger row estimates.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s cool, but this weird bug showed up, too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &amp;ldquo;morally equivalent plan&amp;rdquo; XML has the wrong &lt;code&gt;query_hash&lt;/code&gt; value in it. It&amp;rsquo;s stored the &lt;code&gt;query_plan_hash&lt;/code&gt; as the &lt;code&gt;query_hash&lt;/code&gt;, too!&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;query_plan_hash&lt;/code&gt; in the execution plan for plan_id = 11 does not match the &lt;code&gt;query_hash&lt;/code&gt; in &lt;code&gt;sys.query_store_query&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s what this looks like when viewed in the query plan properties in SSMS:&lt;/p&gt;
&lt;figure class="blog-image"&gt;&lt;img src="https://kendralittle.com/images/query_store_query_hash-identical_to_query_plan_hash.png"
alt="Screenshot of query plan properties in SSMS showing query hash identical to query plan hash"&gt;
&lt;/figure&gt;
&lt;h2 id="it-gets-worse-further-executions-make-the-query_hash-incorrect-for-every-row-with-this-query_id-in-sysquery_store_query"&gt;It Gets Worse: Further Executions Make the Query_hash Incorrect for Every Row with This Query_id in Sys.query_store_query&lt;/h2&gt;
&lt;p&gt;Now run the stored procedure for another value:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostsForDisplayname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Kendra&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rerunning the same query to check &lt;code&gt;query_hash&lt;/code&gt; values in the dynamic management views shows that we have a new &amp;ldquo;morally equivalent plan&amp;rdquo; added.&lt;/p&gt;
&lt;p&gt;And the Query Store DMVs have now become infected with that messed up &lt;code&gt;query_hash&lt;/code&gt; value.&lt;/p&gt;
&lt;figure class="blog-image"&gt;&lt;img src="https://kendralittle.com/images/query_store_query_hash-all-messed-up.png"
alt="Screenshot of Query Store DMVs showing corrupted query hash values"&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;ve extracted the data for query_id 7 to text, which is:&lt;/p&gt;
&lt;table class="blog-table" id="table_query_hash_all_messed_up"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Query Id&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Plan Id&lt;/th&gt;
&lt;th&gt;Query Hash sys.query_store_query&lt;/th&gt;
&lt;th&gt;Query Plan Hash sys.query_store_plan&lt;/th&gt;
&lt;th&gt;Query Hash in Plan XML&lt;/th&gt;
&lt;th&gt;Query Plan Hash in Plan XML&lt;/th&gt;
&lt;th&gt;Is Use Plan Hint in Plan?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0x44A186BFC52AA053&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x44A186BFC52AA053&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0x56049465CF9FFB95&lt;/td&gt;
&lt;td&gt;0xD55EEC4C7A81E644&lt;/td&gt;
&lt;td&gt;0x56049465CF9FFB95&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0x61807D991A7B6914&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0x868D1CD7976DCFF8&lt;/td&gt;
&lt;td&gt;0x868D1CD7976DCFF8&lt;/td&gt;
&lt;td&gt;0x868D1CD7976DCFF8&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Now we are in a state where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One &amp;ldquo;morally equivalent&amp;rdquo; query plan has erroneously set its &lt;code&gt;query_hash&lt;/code&gt; value to the &lt;code&gt;query_plan_hash&lt;/code&gt; value in the plan XML&lt;/li&gt;
&lt;li&gt;Another &amp;ldquo;morally eqivalent&amp;rdquo; plan being generated has caused the &lt;code&gt;query_hash&lt;/code&gt; value in &lt;code&gt;sys.query_store_query&lt;/code&gt; to be bizarrely updated to the value of the &lt;code&gt;query_plan_hash&lt;/code&gt; for one of the plans.&lt;/li&gt;
&lt;li&gt;We have three query plans where the &lt;code&gt;query_hash&lt;/code&gt; value in the plan XML does not match the &lt;code&gt;query_hash&lt;/code&gt; value in &lt;code&gt;sys.query_store_query&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If we have any tooling that has recorded the previous &lt;code&gt;query_hash&lt;/code&gt; value of &lt;code&gt;0xD55EEC4C7A81E644&lt;/code&gt; for this query, it (or you) will no longer find that in &lt;code&gt;sys.query_store_query&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="update-im-not-the-first-to-find-this-bug-and-i-probably-wont-be-the-last"&gt;Update: I&amp;rsquo;m Not the First to Find This Bug, and I Probably Won&amp;rsquo;t be the Last&lt;/h2&gt;
&lt;p&gt;I was inspired to write this post after &lt;a href="https://gohigh.substack.com/"&gt;Haripriya Naidu&lt;/a&gt; asked at PASS Data Community Summit if anyone else had seen this behavior, and I had &amp;ndash; I&amp;rsquo;d just been so burnt out on filing bugs with Microsoft that I hadn&amp;rsquo;t found the energy to document and report it. (&lt;a href="https://kendralittle.com/2024/09/23/how-survive-microsoft-support-ticket-sql-server-azure-sql/"&gt;It&amp;rsquo;s a lousy customer experience&lt;/a&gt;.) But the fact that Haripriya asked made me feel like it was worth it.&lt;/p&gt;
&lt;p&gt;Paul White has written a great post digging into this, &lt;a href="https://www.sql.kiwi/2024/11/forced-plans-query-hash/"&gt;SQL Server Forced Plans Overwite the Query Hash&lt;/a&gt;. Paul shows a much simpler way to reproduce this than I have here, simply with a &lt;code&gt;use plan&lt;/code&gt; hint. (I do think the repro in this post still adds some value by showing how the issue spreads in Query Store.)&lt;/p&gt;
&lt;p&gt;Paul writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This bug affects SQL Server 2008 to 2022 CU16 inclusive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He clarifies in a note:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Only guided plan search is affected. Supplying individual query hints (except USE PLAN of course) in a plan guide (or via an equivalent feature) does not provoke this misbehaviour.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Paul also references that this problem appeared in posts by &lt;a href="https://sql-sasquatch.blogspot.com/2019/06/sql-server-query-store-usability-soft_17.html"&gt;SQL Sasquatch, aka @sql_handle back in 2019&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7266536271735394305/"&gt;Tomáš Zíka also posted about this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have chatted with a Product Managers at Microsoft in a LinkedIn DM about this who works with the teams in this area. They were receptive to hearing about this issue&amp;ndash; and they even started looking into it during their weekend. I do expect that working through issues like this can take some time for a product like SQL Server, and I&amp;rsquo;m happy that the first steps of finding the right people to communicate the issue to and raising awareness of the bug within the user community seem to be going well.&lt;/p&gt;
&lt;h2 id="what-this-means-if-you-force-query-plans"&gt;What This Means If You Force Query Plans&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m hoping Microsoft recognizes this a bug and fixes the issue, because this makes using Query Store much harder for administrators. I think, most critically, it makes &lt;em&gt;learning&lt;/em&gt; to use Query Store harder.&lt;/p&gt;
&lt;p&gt;First of all, it makes no sense to me that the hashes of two different things (query text and a query plan) would regularly be the same value. Holy hash collision, Batman. It just is confusing.&lt;/p&gt;
&lt;p&gt;But this also means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can&amp;rsquo;t reliably use the &lt;code&gt;query_hash&lt;/code&gt; value from an execution plan that you find with a tool like &lt;code&gt;sp_WhoIsActive&lt;/code&gt; or from a monitoring tool to find the query in &lt;code&gt;sys.query_store_query&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;Using the &lt;code&gt;query_plan_hash&lt;/code&gt; and looking it up in &lt;code&gt;sys.query_store_plan&lt;/code&gt; should be more reliable, but you have to know to do that.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you have a single tenant architecture (multiple copies of the same database schema in production), you can&amp;rsquo;t reliably find the same query across different query stores using the &lt;code&gt;query_hash&lt;/code&gt; value.
&lt;ul&gt;
&lt;li&gt;If query plans have been forced in some places, the &lt;code&gt;query_hash&lt;/code&gt; could be set to who knows what, and you&amp;rsquo;ll incorrectly think the query isn&amp;rsquo;t running there.&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t use &lt;code&gt;query_plan_hash&lt;/code&gt; for this, either, because possibly the query has totally different plans.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;last_compile_batch_sql_handle&lt;/code&gt; in &lt;code&gt;sys.query_store_query&lt;/code&gt; is potentially the best bet at this point. But that&amp;rsquo;s for the entire batch. Maybe &lt;code&gt;statement_sql_handle&lt;/code&gt; in &lt;code&gt;sys.query_store_query_text&lt;/code&gt; is the best bet, because that value is also in query plan xml.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The same thing also goes for queries that you&amp;rsquo;ve saved off in the past and want to examine now, but Query Store data has changed.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>What Is the CPU Wait in Datadog SQL Server Monitoring? How Does It Compare to Waiting on CPU?</title><link>https://kendralittle.com/2024/11/21/what-is-the-cpu-wait-datadog-sql-server/</link><pubDate>Thu, 21 Nov 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/11/21/what-is-the-cpu-wait-datadog-sql-server/</guid><description>&lt;p&gt;I use Datadog on a regular basis, and I&amp;rsquo;m a pretty huge fan. The monitoring pack for SQL Server (and its PAAS variants) is still pretty rudimentary, but it evolves regularly. That&amp;rsquo;s NOT what I&amp;rsquo;m a fan of, though.&lt;/p&gt;
&lt;p&gt;What makes me a raving fan is the flexibility of Datadog&amp;rsquo;s notebooks and dashboards, combined with the ability to create all sorts of custom metrics and monitors. There are &lt;em&gt;always&lt;/em&gt; things in SQL Server monitoring packs that I have strong opinions about. Datadog lets me take what I want, build what I need that isn&amp;rsquo;t contained in that, and ignore the rest. For a team that has the budget to afford Datadog paired with dedicated database staff with the time and resources to do this work, this can be a great fit.&lt;/p&gt;
&lt;p&gt;One of the weirdest and worst parts of the Datadog SQL Server monitoring tooling, though, is how it handles wait stats. In my opinion, it&amp;rsquo;s a case of someone reinventing a wheel that didn&amp;rsquo;t need to be reinvented, and then not documenting what they did clearly (at least not in a way I can find).&lt;/p&gt;
&lt;p&gt;Two of the most confusing Datadog &amp;lsquo;waits&amp;rsquo; are labeled &amp;lsquo;CPU&amp;quot; and &amp;ldquo;Waiting on CPU&amp;rdquo;. I opened a support ticket with Datadog a while back to ask what these are, because I couldn&amp;rsquo;t find any way they correspond to actual wait stats in SQL Server. I learned they aren&amp;rsquo;t wait stats at all. In fact, I think you should largely ignore them. Here&amp;rsquo;s why.&lt;/p&gt;
&lt;!--more=--&gt;
&lt;h2 id="waits-in-datadog-are-all-mixed-up-with-session-status"&gt;Waits in Datadog are All Mixed Up with Session Status&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/datadoggo.png" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;The most important thing I learned from the support ticket is that what are listed as &amp;ldquo;waits&amp;rdquo; in Datadog are purposefully not just the wait types we are familiar with from SQL Server. They have invented the concepts of &amp;ldquo;CPU&amp;rdquo; and &amp;ldquo;Waiting for CPU&amp;rdquo;, which are based on query/session status.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What determines the &amp;ldquo;CPU&amp;rdquo; and &amp;ldquo;Waiting for CPU&amp;rdquo; wait event is a combination of a couple of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The query&amp;rsquo;s current status (pulled from sys.dm_exec_requests (Transact-SQL)).&lt;/li&gt;
&lt;li&gt;The session&amp;rsquo;s current status (pulled from sys.dm_exec_sessions (Transact-SQL)).&lt;/li&gt;
&lt;li&gt;The query&amp;rsquo;s current wait type (pulled from sys.dm_os_wait_stats (Transact-SQL)).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id="the-cpu-wait-isnt-actually-a-wait"&gt;The &amp;ldquo;CPU&amp;rdquo; Wait Isn&amp;rsquo;t Actually a Wait&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an image of how Datadog displays so-called CPU &amp;ldquo;waits&amp;rdquo; &amp;ndash; it&amp;rsquo;s really prominent:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/datadog-cpu-wait.png"&gt;
&lt;/figure&gt;
&lt;p&gt;When you look at these graphs, it&amp;rsquo;s almost impossible to not think this is some kind of representation of a &lt;code&gt;CXPACKET&lt;/code&gt; wait or &lt;code&gt;SOS_SCHEDULER_YIELD&lt;/code&gt;. However, it&amp;rsquo;s not that at all:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the query doesn&amp;rsquo;t have a wait type and the request status is &lt;code&gt;running&lt;/code&gt; or if the session status is &lt;code&gt;running&lt;/code&gt;, then the Wait Event will be CPU.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s just a sample of the number of running queries.&lt;/p&gt;
&lt;p&gt;Why in the world would that be included as a &amp;lsquo;wait&amp;rsquo; and labeled &amp;lsquo;CPU&amp;rsquo;? I don&amp;rsquo;t know that anyone did any user research with DBAs here.&lt;/p&gt;
&lt;p&gt;For workload/activity metrics, I prefer looking at something like batch requests/second. I don&amp;rsquo;t find this sample of executing queries at an instant useful, so I ignore it.&lt;/p&gt;
&lt;h2 id="waiting-on-cpu-isnt-a-wait-either"&gt;&amp;ldquo;Waiting on CPU&amp;rdquo; Isn&amp;rsquo;t a Wait, Either&lt;/h2&gt;
&lt;p&gt;I guess it&amp;rsquo;s a good thing that there&amp;rsquo;s a similarly named wait, &amp;ldquo;Waiting on CPU&amp;rdquo;, because at least that&amp;rsquo;s a clue that a &amp;ldquo;CPU&amp;rdquo; wait isn&amp;rsquo;t the same thing in some way? I donno. Here&amp;rsquo;s what &amp;ldquo;Waiting on CPU&amp;rdquo; looks like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/datadog-waiting-on-cpu-wait.png"&gt;
&lt;/figure&gt;
&lt;p&gt;This so called &amp;ldquo;wait&amp;rdquo; represents a query that is in the runnable queue that isn&amp;rsquo;t running at the instant of the sample:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the query doesn&amp;rsquo;t have a wait type, and the request status is &lt;code&gt;runnable&lt;/code&gt;, then the Wait Event will be WAITING ON CPU.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t think this is particularly useful, either. The SQLOS cycles queries on and off the runnable queue very, very frequently. What&amp;rsquo;s sampled at an instant like this isn&amp;rsquo;t super meaningful to me.&lt;/p&gt;
&lt;h2 id="datadogs-sql-server-monitoring-would-be-better-off-with-a-much-simpler-approach-to-wait-stats"&gt;Datadog&amp;rsquo;s SQL Server Monitoring would be Better Off with a Much Simpler Approach to Wait Stats&lt;/h2&gt;
&lt;p&gt;My take: One of the benefits of SQL Server is that it has very strong documentation and an ecosystem of users who generate a lot of content about things like wait stats. Just show us the waits with their actual names, don&amp;rsquo;t rename them or decode them. Don&amp;rsquo;t make stuff up. That&amp;rsquo;s really all you need to do. Renaming things and making up &amp;ldquo;waits&amp;rdquo; to inject into graphs with confusing names only makes it harder for users to understand your tool.&lt;/p&gt;
&lt;p&gt;But like I said&amp;ndash; I love using Datadog. While I don&amp;rsquo;t find the way it displays SQL Server wait stats super useful, the flexibility of the tooling makes it OK for me to disagree with their take on that and still build observability tooling that does what I need by filtering for the waits I care about and setting up custom metrics that help me alert quickly on problematic situations&amp;ndash; plus I can build in self-healing. And that, dear reader, is glorious.&lt;/p&gt;
&lt;p&gt;Thanks very much to Datadog support for helping me decode this when the answer wasn&amp;rsquo;t clear at all.&lt;/p&gt;</description></item><item><title>How to Survive Opening a Microsoft Support Ticket for SQL Server or Azure SQL</title><link>https://kendralittle.com/2024/09/23/how-survive-microsoft-support-ticket-sql-server-azure-sql/</link><pubDate>Mon, 23 Sep 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/09/23/how-survive-microsoft-support-ticket-sql-server-azure-sql/</guid><description>&lt;p&gt;Asking Microsoft for support for SQL Server or Azure SQL is a lousy experience these days, whether you&amp;rsquo;re using a cheaper service tier or the more expensive support tier formerly known as &amp;ldquo;Premiere Support.&amp;rdquo; You need to know a lot about the root cause of your problem and how to solve it, or your request will be dismissed with misinformation. You&amp;rsquo;ll need data and metrics to back up your claims to get the ticket escalated, and you&amp;rsquo;ll need to provide those receipts multiple times. Once escalated to the Product Group, you may get a helpful response, but it takes a while. If the answer is relayed through a lower support tier, it often won&amp;rsquo;t make much sense.&lt;/p&gt;
&lt;p&gt;These issues aren&amp;rsquo;t due to bad work ethics or personal failings of support workers. These are good humans trying their best. The problem is worse because it&amp;rsquo;s systemic.&lt;/p&gt;
&lt;h2 id="a-culture-of-guessing-at-answers"&gt;A culture of guessing at answers&lt;/h2&gt;
&lt;p&gt;Support staff don&amp;rsquo;t seem equipped to learn about the products they support. There&amp;rsquo;s a culture of guessing at answers, which indicates they lack access to subject matter experts. They also have trouble accessing telemetry for hosted services. I suspect they can&amp;rsquo;t easily see previous messages or emails I&amp;rsquo;ve sent.&lt;/p&gt;
&lt;p&gt;But you&amp;rsquo;ll still need help from Microsoft to report bugs or outages. The support experience is repetitive, time consuming, and frustrating. Here are my tips for making it through as efficiently as possible.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/here-to-help.gif"
alt="Animated GIF showing a character saying &amp;#39;here to help&amp;#39;" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="start-the-ticket-promptly-but-immediately-start-researching-on-your-own"&gt;Start the ticket promptly, but immediately start researching on your own&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll have to be the expert here. Many support employees know just enough to be dangerously wrong.&lt;/p&gt;
&lt;p&gt;With the cheaper support tier, you&amp;rsquo;ll need to persistently restate the exact product you&amp;rsquo;re using. You&amp;rsquo;ll get responses that only apply to a different SQL Server offering—queries that don&amp;rsquo;t run, answers from another universe.&lt;/p&gt;
&lt;p&gt;With the more expensive tier, they understand what product you&amp;rsquo;re using, but knowledge about how it works is very limited. It&amp;rsquo;s like interacting with ChatGPT: you&amp;rsquo;ll get blocks of complex text that don&amp;rsquo;t hold up to scrutiny.&lt;/p&gt;
&lt;p&gt;For example, if you report I/O errors in an Azure SQL Managed Instance error log, you might be told this is how General Purpose throttles storage and you need to pay for a more expensive tier. This could cost a lot, unless you understand that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can prove I/O usage was well below limits using &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-server-resource-stats-azure-sql-database"&gt;sys.server_resource_stats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The error means exactly what it says: 15+ seconds of storage not responding, which is a storage subsystem failure&lt;/li&gt;
&lt;li&gt;This isn&amp;rsquo;t how I/O throttling works on the service&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: Microsoft has announced the general availability of the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;Next-gen General Purpose service tier&lt;/a&gt; for Azure SQL Managed Instance, which includes improvements to I/O latency, IOPS, and transaction log throughput. This section describes errors common on General Purpose V1 blob storage. You don't want that.
&lt;/div&gt;
&lt;p&gt;You might also be told that RECOMPILE hints cause PAGELATCH waits, that you need to be the only active user to shrink a file, or that if a query triggers stack dumps you should just stop running it.&lt;/p&gt;
&lt;p&gt;Support quality has degraded significantly in recent years, partly due to Azure SQL products having similar names, multiple rebrands, and blended documentation. It&amp;rsquo;s hard to learn about these products without real-world experience, and I&amp;rsquo;ve never seen evidence that support staff get that opportunity.&lt;/p&gt;
&lt;h2 id="you-may-need-a-consultant"&gt;You may need a consultant&lt;/h2&gt;
&lt;p&gt;If you don&amp;rsquo;t have someone on staff who understands SQL Server, it&amp;rsquo;s worth hiring a consultant to help manage the support process.&lt;/p&gt;
&lt;p&gt;I realize this feels like it shouldn&amp;rsquo;t be necessary. Microsoft Support &lt;em&gt;should&lt;/em&gt; be better. But I have little hope it will improve soon—Generative AI will have the same problems. Early versions of Gen AI Advice in the Azure Portal already recommend solutions for the wrong product, just like the cheapest support tier.&lt;/p&gt;
&lt;p&gt;Working with someone who knows SQL Server may seem expensive, but so is SQL Server licensing and cloud costs. A good expert will help you call out bad advice from Microsoft Support, which often suggests throwing more money at licenses or Azure to spend the problem away.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think there&amp;rsquo;s nefarious intent from support staff—they&amp;rsquo;re doing their best with the documentation they have, which generally puts an overly optimistic spin on more expensive tiers. But that advice often isn&amp;rsquo;t in your best financial interest and won&amp;rsquo;t work. There&amp;rsquo;s a conflict of interest when your cloud provider also creates the software: organizational incentives are around profit margins, not helping customers find cost-effective solutions.&lt;/p&gt;
&lt;h2 id="keep-all-your-research-in-a-document"&gt;Keep all your research in a document&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll need to provide data repeatedly. Don&amp;rsquo;t fall into the trap of only entering data into the email thread—it gets long, and people miss information.&lt;/p&gt;
&lt;p&gt;I keep a copy of all my research and data in a document so I can quickly restate it without going back through the thread. I imagine support staff can&amp;rsquo;t see anything I provided previously and work as if they&amp;rsquo;re in Memento or Groundhog Day. I can&amp;rsquo;t change the system, but I can make it easier to manage.&lt;/p&gt;
&lt;p&gt;This also makes it easy to share with the team: the problem, data gathered, ticket status, workarounds evaluated, and what we need from support.&lt;/p&gt;
&lt;h2 id="save-blurbs-that-block-common-brush-offs"&gt;Save blurbs that block common brush-offs&lt;/h2&gt;
&lt;p&gt;Support folks work off scripts. You&amp;rsquo;ll quickly notice patterns: if you report unexpected downtime in Azure SQL Database or Managed Instance, you&amp;rsquo;ll get long paragraphs about how your application needs retry logic, suggested as a &amp;ldquo;solution.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If you already have retry logic (like almost every application), save phrases you can use to head these off proactively or redirect back to the real problem. It&amp;rsquo;s not worth writing these each time—you get to work off scripts, too.&lt;/p&gt;
&lt;h2 id="frequently-ask-for-escalation-to-the-product-group"&gt;Frequently ask for escalation to the Product Group&lt;/h2&gt;
&lt;p&gt;If you aren&amp;rsquo;t getting a helpful answer, ask early and often for escalation. Depending on your support contract, there may be several levels needed. Folks in the Product Group know the product well and can diagnose problems. They can fix real bugs and give useful advice.&lt;/p&gt;
&lt;p&gt;Sometimes you can&amp;rsquo;t find the right people. For example, I think nobody is home when it comes to the Change Tracking feature and its intermittent problems with synchronous Availability Groups at high load.&lt;/p&gt;
&lt;p&gt;But most of the time, if I can get an issue escalated with the right supporting data, I get helpful information back. It just takes a while, and I need to do research and testing on my own, plus come up with workarounds.&lt;/p&gt;
&lt;h2 id="someones-going-to-call-at-the-end"&gt;Someone&amp;rsquo;s going to call at the end&lt;/h2&gt;
&lt;p&gt;Microsoft will call you at the end when you&amp;rsquo;ve reached some sort of acceptance about your issue, even if you&amp;rsquo;ve specified you prefer email. I&amp;rsquo;m guessing metrics show that talking to a human lessens frustration. They&amp;rsquo;ll ask how your support experience was.&lt;/p&gt;
&lt;p&gt;Like all the support people involved, this will be a good human trying their best. But this whole system shows little signs of positive change.&lt;/p&gt;</description></item><item><title>SQL Server Page Compression: Should You Worry About CPU Usage Increasing on Inserts, Updates, and Deletes?</title><link>https://kendralittle.com/2024/09/08/sql-server-page-compression-cpu-on-insert-update-delete/</link><pubDate>Sun, 08 Sep 2024 12:48:50 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/09/08/sql-server-page-compression-cpu-on-insert-update-delete/</guid><description>&lt;p&gt;Every time I share a recommendation to use data compression in SQL Server &lt;a href="https://kendralittle.com/2024/08/26/please-compress-indexes-and-shrink-your-database-azure-sql-managed-instance/"&gt;to reduce physical IO and keep frequently accessed data pages in memory&lt;/a&gt;, I hear the same concern from multiple people: won&amp;rsquo;t this increase CPU usage for inserts, updates, and deletes?&lt;/p&gt;
&lt;p&gt;DBAs have been trained to ask this question by many trainings and a lot of online content &amp;ndash; I used to mention this as a tradeoff to think about, myself&amp;ndash; but I&amp;rsquo;ve found this is simply the wrong question to ask.&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;ll share the two questions that &lt;em&gt;are&lt;/em&gt; valuable to ask for your workload.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/compress-corgi.png"&gt;
&lt;/figure&gt;
&lt;h2 id="are-data-modifications-slow-enough-that-they-are-impacting-application-performancecustomer-experience-or-close-to-it"&gt;Are Data Modifications Slow Enough That They are Impacting Application Performance/customer Experience, or Close to It?&lt;/h2&gt;
&lt;p&gt;If you already have a problem where data modifications are problematic and are impacting your customer&amp;rsquo;s experience, have a look at what is causing those problems.&lt;/p&gt;
&lt;p&gt;In this section, I&amp;rsquo;m listing the issues that plague most systems and cause slow modifications. All of these make data modifications increase by &lt;em&gt;seconds&lt;/em&gt; or &lt;em&gt;minutes&lt;/em&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Poorly optimized modification queries &amp;ndash; including using merge syntax&lt;/strong&gt;: If modifications are slow, your first step is to find the query plans and execution statistics for the modification queries. Are they doing lots of reads? Are they having issues with parameter sniffing? Merge statements may save some lines in writing code, but they often create terribly performing execution plans. (Please read &lt;a href="https://michaeljswart.com/2021/08/what-to-avoid-if-you-want-to-use-merge/"&gt;Michael J Swart&amp;rsquo;s post, &amp;ldquo;What to Avoid if You Want to Use MERGE&lt;/a&gt; for even more reasons to avoid merge.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cascading updates/deletes&lt;/strong&gt;: These are a recipe for slowness when it comes to foreign keys in SQL Server. The cascading updates and deletes occur within the calling transaction scope, and the serializable isolation level is used to help ensure data correctness. If you have these in place and are using them, data compression is the last thing I&amp;rsquo;d worry about for slowness on modifications: you&amp;rsquo;ve already got a much bigger monster in the house.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Non-optimized or overloaded triggers&lt;/strong&gt;: Not much explanation needed for this one, I think. Everyone hates digging into trigger code to optimize it, but sometimes you need to put on your hazmat suit and go in there. And sometimes you need to talk to other folks about what business logic can move into application code and not need to run in a trigger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pessimistic isolation levels increasing locking and blocking&lt;/strong&gt;: Sometimes modifications are slow because they can&amp;rsquo;t get the locks needed to commit. SQL Server implements a pessimistic version of the Read Committed isolation level by default, under which readers block writers, and writers block readers. This can massively slow down modifications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Non-indexed foreign key relationship&lt;/strong&gt;: Let&amp;rsquo;s say we have two tables, Invoice and Payment. For every invoice, we might have 0 or more payments. There is a foreign key on Payment.InvoiceId that ensures that all InvoiceIds in Payment have a corresponding &amp;ldquo;parent&amp;rdquo; row in the Invoice table. The bit that most folks miss about this is that when an InvoiceId is updated or deleted in the Invoice table (perhaps for an archive process or a process synchronizing data between sources), the database engine has to make sure that this isn&amp;rsquo;t creating a problem in the foreign key relationship. If Payment.InvoiceId does not have a supporting index and and the Payment table is large, this can make that modification to Invoice very slow. Note: in this case, applying data compression to the structures would likely make the modifications faster, as it&amp;rsquo;s shrinking the structure that has to be scanned. But either way, the foreign key relationship needs a supporting index so it doesn&amp;rsquo;t have to do a scan to check referential integrity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Indexed indexed view lacking appropriate supporting indexes&lt;/strong&gt;: When you create an indexed view that joins between multiple tables, you need to make sure that it doesn&amp;rsquo;t adversely impact modifications to those tables. If you don&amp;rsquo;t have the appropriate indexes on the member tables to support the join columns, data modifications may cause scans of the tables. This is another case where compressing data structures on the member tables could actually speed up modifications by reducing the page count of what is scanned, but really what you need is good indexing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you are concerned about data modification performance, by all means evaluate what is causing your modifications to be slow and solve those problems as a priority!&lt;/p&gt;
&lt;p&gt;But meanwhile DBAs have been trained to worry about data compression. Data compression is generally something that increases data modifications by a matter of &lt;em&gt;milliseconds&lt;/em&gt;. (I say generally only because I&amp;rsquo;m sure there&amp;rsquo;s someone out there who has a horrific schema where data compression manages to increase modification time by a second or more &amp;ndash; there&amp;rsquo;s always an exception.)&lt;/p&gt;
&lt;h2 id="does-data-compression-reduce-your-overall-cpu-usage-this-matters-because-it-can-reduce-your-licensing-costs"&gt;Does Data Compression Reduce Your Overall CPU Usage? This Matters Because It can Reduce Your Licensing Costs&lt;/h2&gt;
&lt;p&gt;This is the valuable question to ask about CPU &amp;ndash; what is the CPU impact that data compression has on your workload overall? This is worth exploring because it can save you significant money.&lt;/p&gt;
&lt;p&gt;I have seen data compression have an impact on CPU by &lt;em&gt;lowering&lt;/em&gt; it for OLTP workloads. This happens when data compression helps reduce the number of physical reads that your system is doing, especially when storage is slow. Here&amp;rsquo;s how the magic works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data compression reduces the amount of data pages an index takes up, both on disk and in memory&lt;/li&gt;
&lt;li&gt;This allows more data to fit into the data cache (buffer pool), which reduces the amount of physical reads for queries&lt;/li&gt;
&lt;li&gt;Reads from memory are MUCH faster than reads from storage, so the amount of time queries take to execute speeds up&lt;/li&gt;
&lt;li&gt;Faster queries mean fewer queries cycling on and off schedulers, there&amp;rsquo;s just more room for everyone &amp;ndash; CPU usage drops&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have you ever noticed that tuning indexes can allow you to dramatically reduce CPU usage on a SQL Server. This works for the exact same reasons.&lt;/p&gt;
&lt;h2 id="but-kendra-i-have-a-narrow-table-thats-modified-a-million-times-a-minute-can-you-prove-it-wont-cause-cpu-problems"&gt;But Kendra, I have a Narrow Table That&amp;rsquo;s Modified a Million Times a Minute, can You Prove It Won&amp;rsquo;t Cause CPU Problems?&lt;/h2&gt;
&lt;p&gt;Not unless you&amp;rsquo;re paying me a consulting rate. Look, I&amp;rsquo;m not telling you to compress EVERY index or to not use common sense. I support you in looking for low hanging fruit, and there is almost always PLENTY of that to spend your time with.&lt;/p&gt;
&lt;h2 id="any-database-change-can-cause-a-regression"&gt;Any Database Change can Cause a Regression&lt;/h2&gt;
&lt;p&gt;Making changes to databases is tough, I get it. SQL Server workloads are quite complex, and even simple &amp;ldquo;best practice&amp;rdquo; changes can cause unexpected regressions. I&amp;rsquo;ve even had adding memory and CPUs to a database instance cause regressions by changing query plans when the optimizer&amp;rsquo;s choice on the new plan wasn&amp;rsquo;t ideal.&lt;/p&gt;
&lt;p&gt;Always be careful applying a change:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use pre-production systems to validate changes.&lt;/li&gt;
&lt;li&gt;Work within your change control process and document what you are deploying, and when.&lt;/li&gt;
&lt;li&gt;Identify how to version control your changes, and understand how you will roll them back if needed.&lt;/li&gt;
&lt;li&gt;Baseline performance before you make changes.&lt;/li&gt;
&lt;li&gt;Deploy changes in discrete chunks.&lt;/li&gt;
&lt;li&gt;Observe how your baseline adjusts as the change burns in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But all that said, data compression in SQL Server is still an underrated and underused feature of Enterprise Edition, and concerns about CPU impact to data modifications unnecessarily block many people from benefiting from the feature. It can speed up many things you would think it might slow down, including even &lt;a href="https://bobpusateri.com/2024/04/compression-datatype-change/"&gt;modifying data types&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Script to Automate Unforcing Failed Forced Plans in Query Store (SQL Server)</title><link>https://kendralittle.com/2024/09/02/free-script-automate-unforcing-failed-forced-plans-query-store-sql-server/</link><pubDate>Mon, 02 Sep 2024 11:35:40 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/09/02/free-script-automate-unforcing-failed-forced-plans-query-store-sql-server/</guid><description>&lt;p&gt;tldr; I&amp;rsquo;ve published a script to loop through all databases on an instance, identify if there are any query plans in a problematic &amp;lsquo;failed&amp;quot; forced state (which can hurt query performance), and un-force them if found. Get the &lt;a href="https://github.com/LitKnd/FreeSQLServerScripts/blob/main/queryStore/dba_QueryStoreUnforceFailed.sql"&gt;dbo.dba_QueryStoreUnforceFailed stored procedure on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This script is designed to work on SQL Server on-prem, in a VM, or in Azure SQL Managed Instance or SQL Server RDS. Since the script is instance-level and loops through all databases, this isn&amp;rsquo;t really designed for Azure SQL Database &amp;ndash; and you don&amp;rsquo;t get a SQL Agent there anyway, so you probably want to change this around for that use case. The script is shared under the MIT license, feel free to contribute code and/or adapt away for your own uses.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="whats-so-bad-about-failed-forced-plans"&gt;What&amp;rsquo;s So Bad About Failed Forced Plans?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/unforce-failed-forced-plans.gif" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;Query plans that have been forced in Query Store may end up with the forcing in a &amp;ldquo;failed&amp;rdquo; state for a variety of reasons.&lt;/p&gt;
&lt;p&gt;Sometimes this might be that a structure in the forced plan is no longer valid&amp;ndash; maybe an index that had been selected in the plan has been dropped or its definition has changed. This plan will have a &lt;code&gt;last_force_failure_reason&lt;/code&gt; of 8712 and a &lt;code&gt;last_force_failure_reason_description&lt;/code&gt; of &lt;code&gt;NO_INDEX&lt;/code&gt; in &lt;code&gt;sys.query_store_plan&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve found that if a forced plan is cancelled by the calling application while it is still compiling, it will have a &lt;code&gt;last_force_failure_reason_description&lt;/code&gt; of &lt;code&gt;GENERAL FAILURE&lt;/code&gt;, and that this scenario can cause serious performance problems by dramatically increasing compilation time while the query has the failed forced plan. See my post &lt;a href="https://kendralittle.com/2024/08/12/query-store-failed-forced-plans-general-failure-even-slower-compile-time/"&gt;General Failure Failed Forced Plans in Query Store Cause Even Slower Compile Times&lt;/a&gt; for a script to reproduce this problem.&lt;/p&gt;
&lt;p&gt;I do think there are likely more scenarios where failed forced plans cause slow compilation, other than the &lt;code&gt;GENERAL FAILURE&lt;/code&gt; state. And failed forced plans do you no good at all&amp;ndash; there is no benefit to leaving them in a failed forced state.&lt;/p&gt;
&lt;p&gt;So if you force plans at all, whether manually or by using the Automatic Plan Correction feature, it is worthwhile to set up a process to check for failed forced plans and un-force them.&lt;/p&gt;
&lt;h2 id="get-the-script"&gt;Get the Script&lt;/h2&gt;
&lt;p&gt;Get the &lt;a href="https://github.com/LitKnd/FreeSQLServerScripts/blob/main/queryStore/dba_QueryStoreUnforceFailed.sql"&gt;dbo.dba_QueryStoreUnforceFailed stored procedure on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="shouldnt-sql-server-un-force-these-itself"&gt;Shouldn&amp;rsquo;t SQL Server Un-force These Itself?&lt;/h2&gt;
&lt;p&gt;I think so. Unfortunately, it does not. Add this to the &amp;ldquo;job security for database specialists&amp;rdquo; file, I suppose.&lt;/p&gt;
&lt;h2 id="ill-be-talking-about-this-and-more-at-pass-community-data-summit-in-november"&gt;I&amp;rsquo;ll be Talking About This and More at Pass Community Data Summit in November&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m giving a regular session, &lt;a href="https://passdatacommunitysummit.com/sessions/1296"&gt;Perf Tuning in Prod: Plan Forcing, Plan Guides, and Plan Correction&lt;/a&gt; in Seattle at the PASS Community Data Summit in November.&lt;/p&gt;
&lt;p&gt;You can save $150 off the 3 day conference registration with the code LITTLEK24. &lt;a href="https://reg.passdatacommunitysummit.com/flow/redgate/summit2024/reg/login"&gt;Register today&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Please Compress Your Indexes and Shrink Your Databases If You Use Azure SQL Managed Instance</title><link>https://kendralittle.com/2024/08/26/please-compress-indexes-and-shrink-your-database-azure-sql-managed-instance/</link><pubDate>Mon, 26 Aug 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/08/26/please-compress-indexes-and-shrink-your-database-azure-sql-managed-instance/</guid><description>&lt;p&gt;Shrinking databases in SQL Server isn&amp;rsquo;t fun &amp;ndash; it&amp;rsquo;s slow, it causes blocking if you forget to use the &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-shrinkfile-transact-sql#wait_at_low_priority-with-shrink-operations"&gt;WAIT_AT_LOW_PRIORITY option&lt;/a&gt;, and sometimes it persistently fails and refuses to budge &lt;a href="https://kendralittle.com/2024/08/20/error-1119-sql-server-shrinking-database-removing-iam-page-failed/"&gt;until you restart the instance&lt;/a&gt;. You only want to shrink a SQL Server database when you&amp;rsquo;ve got a good reason and a lot of patience.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Azure SQL Managed Instance and you haven&amp;rsquo;t already used data compression on your indexes and shrunk your databases, you probably have two good reasons to do both of those things: performance and cost reduction.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/data-file-shrink-sql-server.gif" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="use-page-compression-on-your-data-to-make-the-most-of-memory"&gt;Use Page Compression on Your Data to Make the Most of Memory&lt;/h2&gt;
&lt;p&gt;Compressing indexes reduces the amount of data pages that indexes take up in storage. That reduces the amount of physical reads your queries do to pull that data into memory. That&amp;rsquo;s terrific, but it&amp;rsquo;s only half the benefit: compressing those data pages helps you fit more data into memory at a given time, which further reduces physical IO. Physical IO is your enemy in the video game that is administering Managed Instance.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t get a ton of memory per vCore with Managed Instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standard series hardware: 5.1 GB RAM per vCore. 16 vCore= 81.6GB RAM.&lt;/li&gt;
&lt;li&gt;Premium series hardware: 7 GB RAM per vCore. 16 vCore = 112 GB RAM.&lt;/li&gt;
&lt;li&gt;Premium series memory-optimized hardware: 13.6 GB RAM per vCore. 16 vCore=217GB RAM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these amounts of RAM make me sad. That memory-optimized option doesn&amp;rsquo;t seem very memory-optimized to me. But the lower options are basically anti-patterns. To make a SQL Server workload perform well, you want to make sure you can keep frequently accessed data in cache. This is especially true when you have slow storage, which is the case with Managed Instance.&lt;/p&gt;
&lt;p&gt;Yes, the storage is faster on the Business Critical tier, but at a huge cost&amp;mdash; and even then, it ain&amp;rsquo;t all that fast and your writes will get gated by waits due to synchronous replicas.&lt;/p&gt;
&lt;p&gt;If you can use a combination of compression, data pruning, and index tuning to make the General Purpose tier work for you, you will get a lot more value out of the service, without the synchronous commit waits. But you may have to shrink your databases, too, because&amp;hellip;&lt;/p&gt;
&lt;h2 id="storage-sizes-are-tied-to-vcore-allocation-on-managed-instance"&gt;Storage Sizes are Tied to Vcore Allocation on Managed Instance&lt;/h2&gt;
&lt;p&gt;My least favorite thing about Managed Instance is that the amount of storage you need on an instance can dictate the number of vCores you must allocate. This can really drive up your monthly costs if you have a significant amount of data that is not read often&amp;ndash; and that&amp;rsquo;s the case for most databases that have been around for longer than a year or two.&lt;/p&gt;
&lt;p&gt;Here are some storage limits based on vCores. These limits are for total space used across all system and user databases &amp;ndash; including tempdb. The prices listed are at pay-as-you-go rates as of today in the East US region if you are using &amp;ldquo;memory-optimized&amp;rdquo; hardware:&lt;/p&gt;
&lt;p&gt;General Purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need more than 2TB? 8 vCore minimum. $2,375.04/month for 8TB.&lt;/li&gt;
&lt;li&gt;Need more than 8TB? 16 vCore minimum. $4,753.76 /month for 16TB.&lt;/li&gt;
&lt;li&gt;Need more than 16TB? Sorry, you can&amp;rsquo;t have that. (You can have more cores, but this list is based on storage sizes.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Business Critical:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need more than 1TB? 8 vCore minimum. $3,383.12/month for 2TB.&lt;/li&gt;
&lt;li&gt;Need more than 2TB? 16 vCore minimum. $6,774.24/month for 4TB.&lt;/li&gt;
&lt;li&gt;Need more than 4TB? 24 vCore minimum. $10,037.36/month for 5.5TB.&lt;/li&gt;
&lt;li&gt;Need more than 5.5TB? 32 vCore minimum. $25,364.16/month for 8TB.&lt;/li&gt;
&lt;li&gt;Need more than 8TB? 48 vCore minimum. $38,051.04/month for 12TB.&lt;/li&gt;
&lt;li&gt;Need more than 12TB? 64 vCore minimum. $50,737.92/month for 16TB.&lt;/li&gt;
&lt;li&gt;Need more than 16TB? You can&amp;rsquo;t have that. But you could still pay $96,570.24/month for 16TB at 128vCore. Yikes.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: Business Critical SKUs with more than 24 vCores were not available for pricing at the time of this writing in the East US Region. I had to look in the Central region to get pricing on them. I have found the availability of larger vCore Business Critical instances to vary a lot in East US.
&lt;/div&gt;
&lt;h2 id="dont-shrink-too-far-if-youre-on-general-purpose-v1"&gt;Don&amp;rsquo;t Shrink Too Far If You&amp;rsquo;re on General Purpose V1&lt;/h2&gt;
&lt;p&gt;General Purpose V1 is very odd: &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits?view=azuresql#file-io-characteristics-in-general-purpose-tier"&gt;throughput for your files is determined by their size&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You never want to shrink your files too far, just to end up in a cycle of constant shrinking and growing. But you also don&amp;rsquo;t accidentally dip under some of these IOPS thresholds.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ManagedInstance-GPV1-filesizes.png"&gt;
&lt;/figure&gt;
&lt;p&gt;There is an additional limitation of &amp;ldquo;Max 120 MiB/s per instance&amp;rdquo; for transaction log files under GPV1, and I can confirm that I haven&amp;rsquo;t seen much of a difference in performance between a 130GB log file and a 514GB log file. (I haven&amp;rsquo;t been all that scientific about it, though.)&lt;/p&gt;
&lt;p&gt;Thankfully, this whole &amp;ldquo;IOPS based on file size&amp;rdquo; thing is going away in General Purpose V2 (in Public Preview at this time). But it will always be useful to stay fresh on what limitations apply to your configuration, and what configurations are possible.&lt;/p&gt;
&lt;h2 id="the-cloud-is-different"&gt;The Cloud is Different&lt;/h2&gt;
&lt;p&gt;With on-prem databases, it&amp;rsquo;s often not such a big deal to let &amp;ldquo;maybe someday we will need it&amp;rdquo; types of data collect in your database, sprawling in non-compressed fields of bytes. The cloud is different. With PAAS databases, it can take a bit of time to understand how the various SKU options impact your costs, and how to get the best deal of them.&lt;/p&gt;
&lt;p&gt;To recap, when it comes to Azure SQL Managed Instance, you can get good performance even on General Purpose, but to get there you really need to make your active working set of data fit into memory as much as it possibly can. This list will help you get there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maximize your memory per core with the Memory-Optimized sku (even if it&amp;rsquo;s not all THAT optimized)&lt;/li&gt;
&lt;li&gt;Tune your indexes to minimize reads for your frequent queries&lt;/li&gt;
&lt;li&gt;Delete old data where you can, truncate tables you don&amp;rsquo;t need&lt;/li&gt;
&lt;li&gt;Use page compression on All The Things!&lt;/li&gt;
&lt;li&gt;Shrink your databases if the steps above leave you with significant empty space&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These steps should at least help you lower that storage slider for some cost savings, but it can often help you fit into a smaller vCore count and save &lt;em&gt;loads&lt;/em&gt; of money over time.&lt;/p&gt;
&lt;h2 id="i-do-like-managed-instance--and-im-excited-about-the-future-of-the-general-purpose-tier"&gt;I do Like Managed Instance &amp;ndash; and I&amp;rsquo;m Excited About the Future of the General Purpose Tier&lt;/h2&gt;
&lt;p&gt;While there are many things I want to change about Managed Instance, you can get good value from the service in the right configuration, especially if you work to minimize your costs.&lt;/p&gt;
&lt;p&gt;Here are three things I love about Managed Instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It&amp;rsquo;s good at Availability Groups.&lt;/strong&gt; Whether you are using Business Critical with synchronous AGs or asynchronous AGs in a Failover Group (or both), it really takes the headache out of managing those replicas. This is not an easy thing to automate. I&amp;rsquo;ve found a gotcha or two, but I&amp;rsquo;m super impressed with how well it usually works.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It&amp;rsquo;s not ALL Availability Groups.&lt;/strong&gt; I &lt;em&gt;love&lt;/em&gt; that the General Purpose tier in Managed Instance uses a &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla-local-zone-redundancy?view=azuresql#general-purpose-service-tier"&gt;Failover Cluster like architecture&lt;/a&gt;. I don&amp;rsquo;t want the overhead of synchronous Availability Group replicas unless there is a specific need for them. For many purposes, having a failover cluster architecture in the primary region and an asynchronous secondary using a Failover Group in another region is a terrific fit. This is not available in Amazon RDS for SQL Server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It&amp;rsquo;s much faster than it used to be to create and scale instances&lt;/strong&gt;. A lot of the pains there have been fixed &amp;ndash;as long as you&amp;rsquo;ve got the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/november-2022-feature-wave-for-azure-sql-managed-instance/ba-p/3677741"&gt;2022 feature wave&lt;/a&gt; applied to your subnets. Ask your account rep about upgrading if you&amp;rsquo;ve been using Managed Instance for a while and don&amp;rsquo;t have that, it makes a lot of things better.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ll expand on these in a future post after I look a bit more at &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;General Purpose V2, which is in public preview&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Error 1119 When Shrinking Database: Removing IAM Page Failed</title><link>https://kendralittle.com/2024/08/20/error-1119-sql-server-shrinking-database-removing-iam-page-failed/</link><pubDate>Tue, 20 Aug 2024 19:32:07 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/08/20/error-1119-sql-server-shrinking-database-removing-iam-page-failed/</guid><description>&lt;p&gt;At times when shrinking a data file in a SQL Server or Azure SQL Managed Instance/Database, shrink operations may persistently fail with the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 1119, Level 16, State 1, Line 11
Removing IAM page ([filenumber]:[pagenumber]]) failed because someone else is using
the object that this IAM page belongs to. DBCC execution completed. If DBCC printed
error messages, contact your system administrator.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;rsquo;s not much documented on this error anywhere that I can find, so I&amp;rsquo;m sharing my experience with this error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt; I was not able to get past this without restarting the SQL Server service.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/shrink-unicorn.gif"&gt;
&lt;/figure&gt;
&lt;h2 id="how-to-get-past-the-error"&gt;How to Get Past the Error&lt;/h2&gt;
&lt;p&gt;So far, the only way I&amp;rsquo;ve found to get past this error is by restarting the SQL Server service, or accomplishing this by triggering a failover in a managed database environment. I&amp;rsquo;ve asked Microsoft Support to document this error and if there are any fixes other than a service restart.&lt;/p&gt;
&lt;h2 id="shrinkfile-with-notruncate-may-be-helpful-if-you-cant-restart-the-sql-server-service-right-away"&gt;SHRINKFILE with NOTRUNCATE may be Helpful If You Can&amp;rsquo;t Restart the SQL Server Service Right Away&lt;/h2&gt;
&lt;p&gt;If you can&amp;rsquo;t restart the SQL Server service right away, I have found that if you can run the &lt;code&gt;DBCC SHRINKFILE&lt;/code&gt; command with the &lt;code&gt;NOTRUNCATE&lt;/code&gt; option without hitting the error, this can help you make progress on shrink while you wait for a service restart.&lt;/p&gt;
&lt;p&gt;(To be clear, this won&amp;rsquo;t actually shrink any files&amp;ndash; it will only relocate pages within the datafiles. This can make subsequent shrinks move more quickly once you can remove the &lt;code&gt;NOTRUNCATE&lt;/code&gt; option from your command without hitting an error.)&lt;/p&gt;
&lt;h2 id="things-that-did-not-work"&gt;Things That did Not Work&lt;/h2&gt;
&lt;p&gt;I was not able to identify what object the IAM page belonged to&amp;ndash; I believe it was used in a system object and I didn&amp;rsquo;t have the right breadcrumb trail to identify it. There were no longrunning open transactions on the instance. Stopping things like Extended Events traces didn&amp;rsquo;t help. Running &lt;code&gt;SHRINKFILE&lt;/code&gt; with various permutations didn&amp;rsquo;t help either&amp;ndash; shrinking smaller sizes worked to a point, then everything (except shrinking with &lt;code&gt;NOTRUNCATE&lt;/code&gt;) on the data files would stop with the error. The error also happened on multiple data files with different IAM page numbers.&lt;/p&gt;
&lt;p&gt;Microsoft Support recommended running checkdb, which came back clean. They didn&amp;rsquo;t actually recommend the service restart.&lt;/p&gt;</description></item><item><title>General Failure Failed Forced Plans in Query Store Cause Even Slower Compile Times</title><link>https://kendralittle.com/2024/08/12/query-store-failed-forced-plans-general-failure-even-slower-compile-time/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/08/12/query-store-failed-forced-plans-general-failure-even-slower-compile-time/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: Microsoft has announced the general availability of the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;Next-gen General Purpose service tier&lt;/a&gt; for Azure SQL Managed Instance, which includes improvements to I/O latency, IOPS, and transaction log throughput. This post describes the original General Purpose blob storage. You don't want that.
&lt;/div&gt;
&lt;p&gt;This post demonstrates two related bugs with plan forcing in Query Store which increase the likelihood of slower query execution and application timeouts in SQL Server environments.&lt;/p&gt;
&lt;p&gt;These bugs are most likely to impact you if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You use the Automatic Plan Correction feature in SQL Server, which automatically forces query plans.&lt;/li&gt;
&lt;li&gt;Anyone manually forces query plans with Query Store.&lt;/li&gt;
&lt;li&gt;You have slow storage, which can increase your likelihood of having longer compilation times.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The General Purpose tier of Azure SQL Managed Instance and Azure SQL Database feature both slow storage and Automatic Plan Correction enabled by default. So, weirdly enough, your risks of suffering from this problem are high if you are an Azure SQL customer.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt; for his help in diagnosing and reproducing these issues&amp;ndash; and his &amp;lsquo;slow compiler&amp;rsquo; query used in this post was incredibly helpful to isolate and narrow down these problems.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/sql_server_optimizer_oops.png" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="the-two-bugs"&gt;The Two Bugs&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If a query has a forced plan in query store and the query is cancelled by the calling user/application while the query is still compiling (which does still happen for queries with forced plans), it will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generate a &lt;code&gt;query_store_plan_forcing_failed&lt;/code&gt; event without a clear error message &lt;code&gt;(Error: 316, Severity:-1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The query will have the count of failures incremented in sys.query_store_plan&lt;/li&gt;
&lt;li&gt;The last_force_failure_reason_desc column will be set to &lt;code&gt;GENERAL_FAILURE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Following this, the query will have slower or potentially infinite compile time whenever it needs to recompile.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The query used here to reproduce this issue normally takes 28 seconds to compile on my laptop.&lt;/li&gt;
&lt;li&gt;When in a &lt;code&gt;GENERAL_FAILURE&lt;/code&gt; state it takes more than an hour to compile. (I got tired of waiting and cancelled it at that point.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;General failure is about right.&lt;/p&gt;
&lt;h2 id="we-can-reproduce-these-problems-with-an-empty-database"&gt;We can Reproduce These Problems with an Empty Database&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This demo does some things that you wouldn&amp;rsquo;t want to do on a production system, use a test system instead. I reproduced this issue on Microsoft SQL Server 2022 (RTM-CU7) (KB5028743) - 16.0.4065.3 (X64)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, create a database with Query Store enabled:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;QueryStoreTest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryStoreTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SINGLE_USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IMMEDIATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryStoreTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryStoreTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryStoreTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* These options for testing, NOT prod */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryStoreTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OPERATION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;READ_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_STORAGE_SIZE_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INTERVAL_LENGTH_MINUTES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE_BASED_CLEANUP_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WAIT_STATS_CAPTURE_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryStoreTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="start-the-slow-compiler-example-query-in-session-a"&gt;Start the &amp;ldquo;Slow Compiler&amp;rdquo; Example Query in Session A&lt;/h2&gt;
&lt;p&gt;Start this query in one session, let&amp;rsquo;s call it Session A. Thanks to &lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt; for this portable example of a slow-compiling query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATISTICS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;p9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="watch-compilation-time-with-sysdm_tran_active_transactions-in-session-b"&gt;Watch Compilation Time with sys.dm_tran_active_transactions in Session B&lt;/h2&gt;
&lt;p&gt;Monitor how long it takes to compile by running this query in another session, let&amp;rsquo;s call it Session B.. I&amp;rsquo;m currently seeing around 28 seconds on my laptop. The first query doesn&amp;rsquo;t need to complete execution, it only needs to complete compiling. Cancel the query after it finishes compiling&amp;ndash; you&amp;rsquo;ll know that happens when the query no longer shows up as a row in the query in Session B..&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transaction_begin_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_begin_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SECOND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_begin_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYSDATETIME&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_tran_active_transactions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sqlsource_transform&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This images shows Session B when the query from Session A had been compiling for 26 seconds:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/20240811-long-compiler.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Shortly after this point, it finishes compiling and no longer shows up as a result of this query.&lt;/p&gt;
&lt;h2 id="find-the-query-id-and-plan-info-in-query-store-and-force-the-plan"&gt;Find the Query Id and Plan Info in Query Store and Force the Plan&lt;/h2&gt;
&lt;p&gt;In session B, run this query to find the &lt;code&gt;query_id&lt;/code&gt; and &lt;code&gt;plan_id&lt;/code&gt; for the long compiler. (I&amp;rsquo;ll refer to this as the &amp;lsquo;Query Store Status Query&amp;rsquo; in following steps.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_compile_sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_compile_duration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_compile_sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_compile_duration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_forced_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_forced_plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;force_failure_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;force_failure_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_forcing_type_desc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_forcing_type_desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_force_failure_reason_desc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_force_failure_reason_desc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%(SELECT * FROM (VALUES ( 1 , 2), ( 1 , 2)) AS v(i,j) ),%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my case, this is &lt;code&gt;query_id&lt;/code&gt; = 2 and &lt;code&gt;plan_id&lt;/code&gt; = 2.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/20240811-query_id_for_long-compiler.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Run the following query in Session B to force the plan. Specify the correct query id and plan id that you identified in the query above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After forcing the plan, rerun the Query Store Status Query and you should see that the plan has been forced. There haven&amp;rsquo;t been any failures so far.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/20240811-forced_plan_long_compiler.png"&gt;
&lt;/figure&gt;
&lt;h2 id="optional-configure-an-extended-events-trace"&gt;Optional: Configure an Extended Events Trace&lt;/h2&gt;
&lt;p&gt;If you would like, you can now create and start an Extended Events session looking for the &lt;code&gt;query_store_plan_forcing_failed&lt;/code&gt; event. It will fire when you do this next step.&lt;/p&gt;
&lt;h2 id="clear-the-procedure-cache-then-restart-the-long-compiler-query-and-cancel-it-immediately"&gt;Clear the Procedure Cache, Then Restart the Long Compiler Query and Cancel It Immediately&lt;/h2&gt;
&lt;p&gt;We need to do something to cause the query to recompile. For real world queries, this might be an automatic statistics update, a failover, or anything else that triggers a fresh compilation.&lt;/p&gt;
&lt;p&gt;After doing this sequence of events, rerun the Query Store Metadata Query to review the status now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;forced_failure_count&lt;/code&gt; = 1
&lt;code&gt;last_force_failure_reason_desc&lt;/code&gt; = &lt;strong&gt;GENERAL_FAILURE&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/20240811-forced_plan_long_compiler_general_failure.png"&gt;
&lt;/figure&gt;
&lt;h2 id="restart-the-long-compiler-query-above-for-the-third-time-its-even-slower"&gt;Restart the Long Compiler Query Above for the Third Time: It&amp;rsquo;s Even Slower&lt;/h2&gt;
&lt;p&gt;Monitor its compilation time in Session B using &lt;code&gt;sys.dm_tran_active_transactions&lt;/code&gt; to look for &amp;lsquo;sqlsource_transform` as before.&lt;/p&gt;
&lt;p&gt;It will compile for a very long time &amp;ndash; more than 1 hour on my laptop.&lt;/p&gt;
&lt;p&gt;Here it is at 8 minutes, still compiling:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/20240811-long-compiler-8-minutes-now.png"&gt;
&lt;/figure&gt;
&lt;p&gt;And here it is just past an hour, still compiling:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/20240811-long-compiler-hour.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Reminder: these extra-long compile times &lt;a href="https://kendralittle.com/2024/03/05/long-compilers-who-time-out-not-in-query-store/"&gt;will not be written to Query Store if the query is cancelled before compilation finishes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This invisibility in Query Store makes identifying and diagnosing this issue even tricker than normal. Any external monitoring you have may report queries as having run and timed out over and over again, but when you look in Query Store, you don&amp;rsquo;t see the query even executing.&lt;/p&gt;
&lt;h2 id="what-should-microsoft-do-about-this"&gt;What should Microsoft do About This?&lt;/h2&gt;
&lt;p&gt;It feels to me like there are multiple bugs in here that Microsoft should fix:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A query that is cancelled during a compilation timeout does not seem like it should result in a &lt;code&gt;GENERAL_FAILURE&lt;/code&gt; status in Query Store when a plan is forced. Applications can have timeouts set at all sorts of things.&lt;/li&gt;
&lt;li&gt;Plans with &lt;code&gt;GENERAL_FAILURE&lt;/code&gt; as a plan forcing status should not take longer to compile.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I do not think Automatic Plan Correction should be enabled by default in Azure SQL Managed Instance or Azure SQL Database.&lt;/p&gt;
&lt;p&gt;I have reported these issues to Microsoft via a support ticket.&lt;/p&gt;
&lt;h2 id="what-should-users-do-about-this"&gt;What should Users do About This?&lt;/h2&gt;
&lt;p&gt;If you ever force plans&amp;mdash; and especially if you use the Automatic Plan Correction feature, which frequently forces plans&amp;ndash; you should create a SQL Server Agent Job that regularly looks for failed forced plans with a status of &lt;code&gt;GENERAL_FAILURE&lt;/code&gt; and unforce them.&lt;/p&gt;
&lt;p&gt;Consider turning off Automatic Plan Correction if you have it enabled.&lt;/p&gt;</description></item><item><title>Slow Storage Can Cause Slow Compilation Time in SQL Server</title><link>https://kendralittle.com/2024/08/08/slow-storage-can-cause-slow-compilation-time-sql-server/</link><pubDate>Thu, 08 Aug 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/08/08/slow-storage-can-cause-slow-compilation-time-sql-server/</guid><description>&lt;p&gt;Up till now, I&amp;rsquo;ve thought of compilation time in SQL Server as being dependent only on CPU resources&amp;ndash; not something that requires fast storage to be speedy. But that&amp;rsquo;s not &lt;em&gt;quite&lt;/em&gt; right.&lt;/p&gt;
&lt;p&gt;Slow storage can result in periodic long compile time in SQL Server. And long compile time not only extends the runtime for the query, it can also result in blocking with waits for compile locks.&lt;/p&gt;
&lt;p&gt;Thanks to Erik Darling for helping me figure this out, and explaining this all in his video, &lt;a href="https://erikdarling.com/what-else-happens-when-queries-try-to-compile-in-sql-server-compile-locks/"&gt;What Else Happens When Queries Try To Compile In SQL Server: COMPILE LOCKS!&lt;/a&gt;. For great details and demos, go watch that! I&amp;rsquo;ll be working through the topic with some simple flow charts here.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="synchronous-auto-update-of-statistics-and-compilation-time"&gt;Synchronous Auto-update of Statistics and Compilation Time&lt;/h2&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
flowchart LR
id1["`Synchronous
Statistics
Updates`"] --&gt; id2["`Long
Compilation
Time for a Query`"]
&lt;/div&gt;
&lt;/center&gt;
&lt;p&gt;Let&amp;rsquo;s unpack this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Statisics&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Statistics are objects that store information describing the distribution of data in a column or index. Statistics help the query optimizer identify efficient ways to execute a query by providing row estimates, which influences the selection of indexes and physical join types.&lt;/li&gt;
&lt;li&gt;Databases in SQL Server default to automatically refreshing statistics when the data in a table changes significantly. This is great, it helps the query optimizer have a better chance at creating fast execution plans without human intervention.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;There are two modes for auto-update of statistics in SQL Server&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Synchronous stats updates (default): The query that triggers the statistics update waits for the update to complete before executing. This ensures the query uses the most up-to-date statistics but can cause a delay in execution. The most common misunderstanding here is that the query triggering statistics update will be a query that modifies the data. In fact, it is a query that needs to &lt;em&gt;read&lt;/em&gt; from the table and use the statistics in optimization that triggers the auto update of statistics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Asynchronous Stats Updates: The query proceeds without waiting for the statistics to be updated. The stats are updated in the background&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;This avoids delays for the query which triggers the automatic statistics update, but may result in the query using outdated statistics. This may increase the chances of that query getting an inefficient query plan.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Here&amp;rsquo;s what I didn&amp;rsquo;t realize&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I had previously thought that under the synchronous mode of auto-update statistics, queries would wait to &lt;strong&gt;start&lt;/strong&gt; compiling until the statistics were updated. In fact, that period of time waiting for statistics to update is counted as part of compilation time. (You can see this in &lt;a href="https://erikdarling.com/what-else-happens-when-queries-try-to-compile-in-sql-server-compile-locks/"&gt;Erik&amp;rsquo;s demo&lt;/a&gt;.) There is a wait statistic, &lt;code&gt;WAIT_ON_SYNC_STATISTICS_REFRESH&lt;/code&gt;, which&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Occurs when waiting for synchronous statistics update to complete before query compilation and execution can resume.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql"&gt;sys.dm_os_wait_stats docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That description does say that compilation is effectively paused / has started when this wait happens. However, this wait is not surfaced in actual execution plans.&lt;/p&gt;
&lt;p&gt;It is also not tracked in Query Store:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Query Store tracks wait stats only during query execution, not during query compilation. This restricts Query Store&amp;rsquo;s ability to track compilation wait stats.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-store-wait-stats-transact-sql"&gt;sys.query_store_wait_stats&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, long compilation times that you see in query store may or may not be long because of a wait on synchronous stats update OR a wait on compilation locks. You can&amp;rsquo;t tell from just query store. (Reminder: if your queries have a timeout while still in the compilation phase, they will &lt;a href="https://kendralittle.com/2024/03/05/long-compilers-who-time-out-not-in-query-store/"&gt;NOT be recorded in query store for that execution at all&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="compile-lock-waits-and-blocking"&gt;Compile Lock Waits and Blocking&lt;/h2&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
flowchart LR
id1["`Synchronous
Statistics
Updates`"] --&gt; id2["`Long
Compilation
Time for a Query`"]--&gt; id3["`Query Holds
Compile Lock`"]
--&gt; id4["`Other sessions
running the
same query
are blocked`"]
&lt;/div&gt;
&lt;/center&gt;
&lt;p&gt;When you have slow storage and synchronous stats auto-updates, you are more likely to have long compilation times (because of what we described above), and you are therefore more likely to see compilation lock waits. This is especially true in an OLTP workload where some queries are run very frequently from multiple sessions, and are likely to run concurrently.&lt;/p&gt;
&lt;p&gt;Compile locks in SQL Server prevent changes to the plan cache during query compilation to ensure consistency. If we run the exact same procedure or parameterized query from multiple sessions, and one is having a long compile time, the others wait until it has compiled and cached the plan. They can then pull this plan from the cache and off they go.&lt;/p&gt;
&lt;p&gt;This is great when compilation is fast. But when compilation time starts taking 20 seconds, 30 seconds, or longer, this can become quite disruptive.&lt;/p&gt;
&lt;h2 id="how-do-you-fix-this"&gt;How do You Fix This?&lt;/h2&gt;
&lt;p&gt;I think the easiest thing to monitor for is the presence of &lt;code&gt;WAIT_ON_SYNC_STATISTICS_REFRESH&lt;/code&gt; waits. If you don&amp;rsquo;t have those waits, long compilation time is not related to waiting on synchronous stats updates.&lt;/p&gt;
&lt;p&gt;If you do see those waits, look for blocking on compilation locks. This can help you identify which queries are impacted by this. If it&amp;rsquo;s only a few queries, you may want to work at simplifying those queries.&lt;/p&gt;
&lt;p&gt;If it&amp;rsquo;s not just a small set of queries, consider changing your database setting and using asynchronous statistics updates on the database. There&amp;rsquo;s a few disclaimers when it comes to async stats updates. As mentioned above, this setting may result in the query which triggers automatic stats update using outdated statistics. This may increase the chances of that query getting an inefficient query plan.&lt;/p&gt;
&lt;p&gt;But additionally, Microsoft warns:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Asynchronous statistics update is performed by a background request. When the request is ready to write updated statistics to the database, it attempts to acquire a schema modification lock on the statistics metadata object. If a different session is already holding a lock on the same object, asynchronous statistics update is blocked until the schema modification lock can be acquired. Similarly, sessions that need to acquire a schema stability (&lt;code&gt;Sch-S&lt;/code&gt;) lock on the statistics metadata object to compile a query can be blocked by the asynchronous statistics update background session, which is already holding or waiting to acquire the schema modification lock. Therefore, for workloads with very frequent query compilations and frequent statistics updates, using asynchronous statistics can increase the likelihood of concurrency issues due to lock blocking.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/statistics/statistics?view=sql-server-ver16#auto_update_statistics_async"&gt;Statistics docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is a setting that can help with this if you are running SQL Server 2002, Azure SQL Database, or Azure SQL Managed Instance:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In Azure SQL Database, Azure SQL Managed Instance, and beginning in SQL Server 2022 (16.x), you can avoid potential concurrency issues using asynchronous statistics update if you enable the &lt;code&gt;ASYNC_STATS_UPDATE_WAIT_AT_LOW_PRIORITY&lt;/code&gt; database-scoped configuration. With this configuration enabled, the background request will wait to acquire the schema modification (&lt;code&gt;Sch-M&lt;/code&gt;) lock and persist the updated statistics on a separate low-priority queue, allowing other requests to continue compiling queries with existing statistics. Once no other session is holding a lock on the statistics metadata object, the background request will acquire its schema modification lock and update statistics.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/statistics/statistics?view=sql-server-ver16#auto_update_statistics_async"&gt;Statistics docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are more details about this setting in Dimitri Furman&amp;rsquo;s blog post, &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/improving-concurrency-of-asynchronous-statistics-update/ba-p/1441687"&gt;Improving concurrency of asynchronous statistics update&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Consider testing those settings together if you&amp;rsquo;ve got the option.&lt;/p&gt;</description></item><item><title>The Restore-AzSqlInstanceDatabase Long Running Operation Failed Error on Azure SQL Managed Instance</title><link>https://kendralittle.com/2024/05/30/restore-azsqlinstancedatabase-long-running-operation-failed-an-unexpected-error-occured-azure-sql-managed-instance/</link><pubDate>Thu, 30 May 2024 07:56:08 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/05/30/restore-azsqlinstancedatabase-long-running-operation-failed-an-unexpected-error-occured-azure-sql-managed-instance/</guid><description>&lt;p&gt;What&amp;rsquo;s it like to be a Database Administrator for managed databases in Azure? Sometimes it&amp;rsquo;s a painful guessing game when a routine, core operation&amp;ndash; restoring a database &amp;ndash; fails with a most unhelpful error.&lt;/p&gt;
&lt;p&gt;In this case, if the restore is run via PowerShell, following &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/point-in-time-restore?view=azuresql&amp;amp;tabs=azure-powershell#restore-an-existing-database"&gt;Microsoft guidance&lt;/a&gt;, the error message is:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Restore-AzSqlInstanceDatabase: Long running operation failed with status ‘Failed’.
Additional Info: An unexpected error occured while processing the request.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The misspelling of &amp;ldquo;occurred&amp;rdquo; doesn&amp;rsquo;t bring confidence, but we try and try again.&lt;/p&gt;
&lt;h2 id="surely-theres-a-more-clear-error-message-if-you-run-the-restore-in-the-azure-portal-right"&gt;Surely There&amp;rsquo;s a More Clear Error Message If You Run the Restore in the Azure Portal, Right?&lt;/h2&gt;
&lt;p&gt;Nope, if you attempt do to the same operation in the Portal it will fail, and the message there is:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Error code: ResourceOperationFailure
Message: The resource operation completed with terminal provisioning state &amp;#39;Failed&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ooof. So what went wrong?&lt;/p&gt;
&lt;h2 id="i-couldnt-find-the-answers-in-the-sql-server-error-log"&gt;I Couldn&amp;rsquo;t Find the Answers in the SQL Server Error Log&lt;/h2&gt;
&lt;p&gt;One of the benefits of Azure SQL Managed Instance is that it behaves a lot like a &amp;rsquo;normal&amp;rsquo; SQL Server Instance. You can access the SQL Server Error Log.&lt;/p&gt;
&lt;p&gt;But even for core operations like a database restore, it doesn&amp;rsquo;t always contain the info you&amp;rsquo;d expect. In this case I couldn&amp;rsquo;t find any info regarding the restore in the log at all.&lt;/p&gt;
&lt;h2 id="i-couldnt-find-the-answers-on-the-internet-but-i-found-another-customer-who-also-lost-hours-to-this-problem"&gt;I Couldn&amp;rsquo;t Find the Answers on the Internet, but I Found Another Customer Who Also Lost Hours to This Problem&lt;/h2&gt;
&lt;p&gt;I haven&amp;rsquo;t found anything in Microsoft documentation so far explaining what can cause The Vaguest Error Ever.&lt;/p&gt;
&lt;p&gt;I did find a blog post from Mika Sutinen in 2021, &lt;a href="https://sqlstarters.com/2021/03/30/sql-server-managed-instance-and-the-most-unhelpful-error-message-during-a-database-restore/"&gt;SQL Server Managed Instance and the most unhelpful error message during a database restore&lt;/a&gt;. Mika hit the same error message as I did &amp;ndash; and in Mika&amp;rsquo;s case it was worse because they were restoring a large database, so the &amp;ldquo;long running&amp;rdquo; part of the error implied it might be related to the database&amp;rsquo;s size.&lt;/p&gt;
&lt;p&gt;In Mika&amp;rsquo;s case, the database was partially contained and they needed to run some sp_configure commands to get the restore to work. (See the link above for full details.)&lt;/p&gt;
&lt;p&gt;Talk about a needle in a haystack.&lt;/p&gt;
&lt;p&gt;But the database I was restoring wasn&amp;rsquo;t partially contained. I was looking for a different needle.&lt;/p&gt;
&lt;h2 id="in-my-case-it-was-a-transparent-data-encryption-problem"&gt;In My Case, It was a Transparent Data Encryption Problem&lt;/h2&gt;
&lt;p&gt;When using Transparent Data Encryption (TDE):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Backup files for databases that have TDE enabled are also encrypted with the DEK. As a result, when you restore these backups, the certificate that protects the DEK must be available. &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/transparent-data-encryption?view=sql-server-ver16#enable-tde"&gt;Microsoft Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you hit issues restoring a TDE database in &amp;ldquo;normal&amp;rdquo; SQL Server and this isn&amp;rsquo;t configured correctly, you&amp;rsquo;ll receive error messages that give you a good clue &amp;ndash; something along the lines of:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Cannot find server certificate with thumbprint....&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I didn&amp;rsquo;t have access to any such message when restoring my database. And, in fact, I didn&amp;rsquo;t figure it out at all&amp;ndash; my colleague Mike figured it out and ended my suffering after a couple of hours. (Thanks, Mike!)&lt;/p&gt;
&lt;h2 id="better-error-messages-do-show-up-in-some-places"&gt;Better Error Messages do Show Up in Some Places&lt;/h2&gt;
&lt;p&gt;Azure SQL Managed Instance also has a database cloning functionality that uses an AG-like setup under the hood, called &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/database-copy-move-how-to?view=azuresql"&gt;Database Copy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This process seems to use some sort of database restore to seed the AG. If initiating the copy fails, you get a more clear error message.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t great as a workaround, though, because there are a lot of limitations on &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/database-copy-move-how-to?view=azuresql&amp;amp;tabs=azure-portal#limitations"&gt;database copy&lt;/a&gt;, the biggest of which is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The source or destination managed instance shouldn&amp;rsquo;t be configured with a failover group (geo-disaster recovery) setup.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have to choose between maintaining Disaster Recovery and troubleshooting a restore failure, most folks are going to choose keeping DR healthy every time.&lt;/p&gt;
&lt;h2 id="can-someone-please-fix-this"&gt;Can Someone Please Fix This?&lt;/h2&gt;
&lt;p&gt;I created an &amp;ldquo;idea&amp;rdquo; on the Azure feedback site, &lt;a href="https://feedback.azure.com/d365community/idea/d027d287-7d1e-ef11-989a-000d3ad9f523"&gt;Database Restores in the portal and Restore-AzSqlInstanceDatabase should give a helpful error message&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Erik Darling and Kendra Little Rate SQL Server Perf Tuning Techniques</title><link>https://kendralittle.com/2024/05/20/erik-darling-and-kendra-little-rate-sql-server-performance-tuning-techniques/</link><pubDate>Mon, 20 May 2024 10:12:32 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/05/20/erik-darling-and-kendra-little-rate-sql-server-performance-tuning-techniques/</guid><description>&lt;p&gt;Erik Darling joins Kendra Little to rate different SQL Server Performance Tuning Techniques in episode 81 of the Dear SQL DBA podcast. We share our opinions of&amp;hellip; (deep breath)&lt;/p&gt;
&lt;p&gt;Recompile hints, Query Store hints and plan forcing, CTEs, Resource Governor, the legacy cardinality estimator, Table Variables, Automatic Plan Correction, Batch Mode, index rebuilds, Hekaton, NOLOCK, page compression, partitioning, filtered indexes, columnstore, join hints, PSPO, indexed hints, indexed views, optimize for unknown, RCSI, adding more memory, restarting the damn thing, scalar UDFs, and Persisted Memory Grant Feedback.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="listen-to-the-podcast"&gt;Listen to the Podcast&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://traffic.libsyn.com/dearsqldba/dear-sql-dba-erik-and-kendra-rate-perf-tuning-techniques.m4a"&gt;Direct Download Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;Dear SQL DBA on Apple Podcast&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="watch-on-youtube"&gt;Watch on Youtube&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/gaYPyrA92xQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="more-dear-sql-dba"&gt;More Dear SQL DBA&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;episode list&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Finally, a SQL Server Monitoring System That Leverages Query Store</title><link>https://kendralittle.com/2024/05/15/finally-a-sql-server-monitoring-system-query-store/</link><pubDate>Wed, 15 May 2024 19:14:39 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/05/15/finally-a-sql-server-monitoring-system-query-store/</guid><description>&lt;p&gt;I&amp;rsquo;ve spent a bit of time with Microsoft&amp;rsquo;s new &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database-watcher-overview"&gt;database watcher&lt;/a&gt; tool for Azure SQL recently.&lt;/p&gt;
&lt;p&gt;There are a lot of things I like about database watcher&amp;ndash; which is currently in preview and which refuses to Capitalize Its Name&amp;ndash; but it does one big thing that I really, really like: it collects data from Query Store. You can access that Query Store data from built-in database watcher dashboards, query it using KQL, or (something something) in Microsoft Fabric if you&amp;rsquo;ve got money to burn on your monitoring data.&lt;/p&gt;
&lt;p&gt;Query Store has been available since SQL Server 2016, but I haven&amp;rsquo;t yet heard of monitoring tools that truly take advantage of it. It&amp;rsquo;s about time.&lt;/p&gt;
&lt;!--more --&gt;
&lt;h2 id="three-major-sources-to-query-performance-data-from-sql-server"&gt;Three Major Sources to Query Performance Data from SQL Server&lt;/h2&gt;
&lt;p&gt;Most monitoring tools for SQL Server collect fairly similar information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What queries are running at a given time?&lt;/li&gt;
&lt;li&gt;What were their basic metrics like duration, cpu time, logical reads, number of writes, query workspace memory used?&lt;/li&gt;
&lt;li&gt;Were the queries waiting on resources for a significant amount of time, like lock waits?&lt;/li&gt;
&lt;li&gt;What query execution plan was in use?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This data can be gathered from SQL Server in a variety of ways, which have different tradeoffs. Most major monitoring tools for SQL Server use a combination of Plan Cache and Query Stats DMV Sampling as well as some tracing to collect information:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;APPROACH&lt;/th&gt;
&lt;th&gt;PROS&lt;/th&gt;
&lt;th&gt;CONS&lt;/th&gt;
&lt;th&gt;AVAILABILITY&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plan Cache and Query Stats DMV Sampling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Most lightweight polling.&lt;/td&gt;
&lt;td&gt;Limited or missing data for queries with recompile hints, will miss some data whenever plan cache is cleared&lt;/td&gt;
&lt;td&gt;Since SQL Server 2005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;XEvents or SQL Trace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Misses few events, high accuracy&lt;/td&gt;
&lt;td&gt;Heaviest performance impact of the options. Some things, like execution plans, will really slow performance if collected this way.&lt;/td&gt;
&lt;td&gt;Since SQL Server 2005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Query Store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data is kept updated by SQL Server itself and is the basis for many recent SQL Server intelligent query processing (IQP) features&lt;/td&gt;
&lt;td&gt;May not work well with default settings for some workloads, especially if allocated minimal space. Only aggregate performance metrics over specified collection interval. Misses queries that are &lt;a href="https://kendralittle.com/2024/03/05/long-compilers-who-time-out-not-in-query-store/"&gt;cancelled before they finish compiling&lt;/a&gt;.&lt;/td&gt;
&lt;td&gt;Since SQL Server 2016&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="why-isnt-trace-data-or-plan-cache-data-enough"&gt;Why Isn&amp;rsquo;t Trace Data or Plan Cache Data Enough?&lt;/h2&gt;
&lt;p&gt;Plan cache and trace data are certainly useful. Query Store still only collects data from writable primary instances, so for readable secondaries they are the only options we&amp;rsquo;ve got. (&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/query-store-for-secondary-replicas?view=sql-server-ver16"&gt;Query Store for Secondary Replicas&lt;/a&gt;, a sort-of-maybe feature from SQL Server 2022, remains in preview here in May 2024. It is not available even to preview in Azure SQL Database or Managed Instance. It does feel like a lot might be wrong with it, the longer it lingers.)&lt;/p&gt;
&lt;p&gt;But Query Store data is, well, it&amp;rsquo;s just more reliable. When I use a monitoring tool that polls the SQL Server Plan Cache for a lot of its information (which is most of the time these days), I often find that in real world troubleshooting situations that data is just not &lt;em&gt;quite&lt;/em&gt; right. Some things are missing. Some things will be confusing. This is increasingly true for performance issues that slow the whole system down &amp;ndash; external polling for monitoring information is impacted by this as well, and it may completely fail for the most problematic periods.&lt;/p&gt;
&lt;p&gt;I find that in these cases, Query Store contains the information I need to figure out what was going on. Query Store doesn&amp;rsquo;t have complete information &amp;ndash; the monitoring from plan cache is still useful. But when I want a &amp;lsquo;source of truth&amp;rsquo; about query execution plans and aggregate performance metrics, Query Store data is what I want to look at. And if there were major waits &amp;mdash; from tempdb metadata waits to resource_semaphore waits to threadpool waits &amp;mdash; Query Store gathered the data when not much else worked.&lt;/p&gt;
&lt;p&gt;However, I don&amp;rsquo;t want to/ can&amp;rsquo;t maintain Query Store data in every database forever. I don&amp;rsquo;t want it to grow so large that it hits &lt;a href="https://kendralittle.com/2024/04/23/query-store-size-based-cleanup-performance-problems-avoid/"&gt;sized based cleanup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And I also don&amp;rsquo;t love querying production to get performance data, either. I&amp;rsquo;d rather it go into a monitoring system.&lt;/p&gt;
&lt;h2 id="why-arent-all-monitoring-companies-doing-this-for-sql-server"&gt;Why Aren&amp;rsquo;t All Monitoring Companies Doing This for SQL Server?&lt;/h2&gt;
&lt;p&gt;I haven&amp;rsquo;t heard of other SQL Server monitoring tools leveraging Query Store. I did some searching on this to see if this had happened and I hadn&amp;rsquo;t noticed, and found a set of very funny forum posts where users ask if a SQL Server monitoring tool is going to use Query Store, and a sales rep responds with a version of, &amp;lsquo;Hey, we collect all this query data! Look at it! Here&amp;rsquo;s a picture! Please don&amp;rsquo;t notice that I&amp;rsquo;m not answering your question.&amp;quot;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think any of the major SQL Server monitoring tools will likely treat Query Store as a major source of data collection for a while, for largely timing reasons.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most of these products have been established for a while, and they already built a foundation on using the plan cache/ DMVs with some trace data sprinkled in.&lt;/li&gt;
&lt;li&gt;Enterprise sales depend on a tool being able to cover many versions of SQL Server, and lots of folks still run SQL Servers older than 2016.&lt;/li&gt;
&lt;li&gt;Query Store isn&amp;rsquo;t enabled by default in SQL Server databases until SQL Server 2022, and even then it&amp;rsquo;s only for new databases created &amp;ndash; it&amp;rsquo;s not enabled for existing databases on upgrades automatically. There are plenty of SQL Servers where Query Store isn&amp;rsquo;t running.&lt;/li&gt;
&lt;li&gt;Query Store does need to be sized appropriately to avoid cleanup problems or it often slipping into read-only mode, when it doesn&amp;rsquo;t collect data. The plan cache and trace approaches don&amp;rsquo;t have this weakness.&lt;/li&gt;
&lt;li&gt;See my above rude commentary on Query Store for readable secondaries growing old while still stuck in preview.&lt;/li&gt;
&lt;li&gt;A very high number of users don&amp;rsquo;t need super accurate Query Store data &amp;ndash; they aren&amp;rsquo;t specialists. They need simpler, more high level metrics to act on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given all of this, I don&amp;rsquo;t really blame monitoring companies for not rewriting their tooling to rely on Query Store immediately.&lt;/p&gt;
&lt;p&gt;However, I still want Query Store data to be collected into a datastore. I&amp;rsquo;m part of the portion of specialist users who need this data to ensure I&amp;rsquo;m diagnosing a situation accurately and recommending the right course of action. Isn&amp;rsquo;t it about time we got &lt;em&gt;something&lt;/em&gt; in this area?&lt;/p&gt;
&lt;h2 id="why-this-works-for-database-watcher"&gt;Why This Works for Database Watcher&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/query_store_data.png" width="300"&gt;
&lt;/figure&gt;
Database watcher currently supports Azure SQL Managed Instance and Azure SQL Database. Query Store is available to all users of these services, and it&amp;rsquo;s enabled by default when you create a new database.&lt;/p&gt;
&lt;p&gt;While there have been a variety of monitoring-ish tools for Azure SQL over the years, none of them have gotten much traction. They&amp;rsquo;ve all been so similarly named that I never learned how to tell them apart, to be honest. But basically, there was no &amp;ldquo;this has been around for 10 years&amp;rdquo;, robust, widely adopted SQL Server engine monitoring system to displace in Azure.&lt;/p&gt;
&lt;p&gt;A fresh start was made, and when you&amp;rsquo;re making a fresh start with a tool specifically for &amp;ldquo;current&amp;rdquo; Azure SQL Engine versions, using Query Store as a major data source is a clearer choice.&lt;/p&gt;
&lt;p&gt;For me, it&amp;rsquo;s a very refreshing one. I&amp;rsquo;ve already found data in database watcher that has helped solve tough problems.&lt;/p&gt;
&lt;p&gt;One final note: having a monitoring system collect data from Query Store helps you balance Query Store size and data retention settings&amp;ndash; if the data is being collected by database monitor, you don&amp;rsquo;t need to retain nearly as much history in the production database. That makes managing Query Store size easier, and things work better all around.&lt;/p&gt;
&lt;p&gt;Hopefully other monitoring solutions add Query Store in as a data source before another 8 years go by.&lt;/p&gt;</description></item><item><title>Learn Perf Tuning in 2 Days at PASS Summit 2024 With Erik Darling and Kendra Little</title><link>https://kendralittle.com/2024/05/01/two-precons-performance-tuning-pass-summit-2024-erik-darling-kendra-little/</link><pubDate>Wed, 01 May 2024 08:15:30 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/05/01/two-precons-performance-tuning-pass-summit-2024-erik-darling-kendra-little/</guid><description>&lt;p&gt;I&amp;rsquo;m teaming up with Erik Darling to teach you SQL Server Performance Tuning in two days at the PASS Data Community Summit in Seattle.&lt;/p&gt;
&lt;p&gt;Erik and I are co-teaching both days of training to give you a strong strategic background on the internals you need to know, along with critical tactical performance tuning techniques. Join us to level up your perf tuning skills!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/free-sql-comics/pass-precons-performance-tuning-2024-erik-darling-kendra-little.gif"&gt;
&lt;/figure&gt;
&lt;h2 id="about-erik-darling-and-kendra-little"&gt;About Erik Darling and Kendra Little&lt;/h2&gt;
&lt;p&gt;Erik Darling is the founder of &lt;a href="https://erikdarling.com/"&gt;Erik Darling Data&lt;/a&gt;. Erik is a top consultant who helps customers around the world troubleshoot SQL Server performance problems and write reliably fast T-SQL, against all odds, every day.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m Kendra Little. These days I&amp;rsquo;m a Staff Database Reliability Engineer in cannabis tech, a rapidly growing industry with super high performance requirements. I help developers write and tune TSQL using Azure SQL, observability tooling, and lots of automation.&lt;/p&gt;
&lt;p&gt;Together, Erik and I bring a road-tested, proven understanding of SQL Server internals: we teach you what you need to know to get the job done without wandering too far into the weeds of confusion. We&amp;rsquo;ll share which techniques really work, what features are mostly hype, and how to solve a tricky problem without your clever solution falling apart at the seams.&lt;/p&gt;
&lt;h2 id="day-1---practical-guide-to-performance-tuning-internals"&gt;Day 1 - Practical Guide to Performance Tuning Internals&lt;/h2&gt;
&lt;p&gt;Whether you’re aiming to be the next great query tuning wizard or you simply need to tackle tough business problems at work, you need to understand what makes a workload run fast&amp;ndash; and especially what makes it run slowly.&lt;/p&gt;
&lt;p&gt;Erik Darling and Kendra Little will show you the practical way forward, and will introduce you to the internal subsystems of SQL Server with a practical guide to their capabilities, weaknesses, and most importantly what you need to know to troubleshoot them as a developer or DBA. They’ll teach you how to use your understanding of the database engine, the storage engine, and the query optimizer to analyze problems and identify what is a nothingburger best practice and what changes will pay off with measurable improvements.&lt;/p&gt;
&lt;p&gt;With a blend of bad jokes, expertise, and proven strategies, Erik and Kendra will set you up with practical skills and a clear understanding of how to apply these lessons to see immediate improvements in your own environments.&lt;/p&gt;
&lt;h2 id="day-2---query-quest-conquer-sql-server-performance-monsters"&gt;Day 2 - Query Quest: Conquer SQL Server Performance Monsters&lt;/h2&gt;
&lt;p&gt;Picture this: a day crammed with fun, fascinating demonstrations for SQL Server and Azure SQL. This isn’t your typical training day; this session follows the mantra of “learning by doing,” with a good dose of the unexpected.&lt;/p&gt;
&lt;p&gt;Think of this as a SQL Server video game, where Erik and Kendra guide you through levels of weird query monsters and performance tuning obstacles. By the time we reach the final boss, you&amp;rsquo;ll have developed an appetite for exploring the unknown and leveled up your confidence to tackle even the most daunting of database dilemmas. It&amp;rsquo;s SQL Server, but not as you know it—more fun, more fascinating, and more scalable than you thought possible.&lt;/p&gt;
&lt;h2 id="q-is-day-1-required-to-understand-day-2-does-day-2-repeat-material"&gt;Q: is Day 1 Required to Understand Day 2? does Day 2 Repeat Material?&lt;/h2&gt;
&lt;p&gt;Nope! These two days are designed to compliment one another without repeating material: each precon is a force multiplier for the other, but each day also can stand alone and be fully understandable.&lt;/p&gt;
&lt;h2 id="join-us-in-seattle-on-november-4-and-5-at-pass-data-community-summit"&gt;Join Us in Seattle on November 4 and 5 at Pass Data Community Summit!&lt;/h2&gt;
&lt;p&gt;Hope to see you there :)&lt;/p&gt;</description></item><item><title>Query Store Size Based Cleanup Causes Performance Problems - How to Avoid It</title><link>https://kendralittle.com/2024/04/23/query-store-size-based-cleanup-performance-problems-avoid/</link><pubDate>Tue, 23 Apr 2024 07:47:55 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/04/23/query-store-size-based-cleanup-performance-problems-avoid/</guid><description>&lt;p&gt;I&amp;rsquo;m a huge fan of SQL Server&amp;rsquo;s Query Store feature. Query Store collects query execution plans and aggregate query performance metrics, including wait stats. Having Query Store enabled makes troubleshooting performance issues such as bad parameter sniffing, much, much easier. Because Query Store is integrated into SQL Server itself, it also can catch query plans in a lightweight way that an external monitoring system will often miss.&lt;/p&gt;
&lt;p&gt;When performance matters, it&amp;rsquo;s important to ensure that you&amp;rsquo;re managing Query Store so that Query Store cleanup does not run during high volume times. Query Store cleanup could slow your workload down significantly.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/query-store-hornet-attack.gif" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="look-out-the-cleanup-hornets-are-coming"&gt;Look Out, the Cleanup Hornets are Coming&lt;/h2&gt;
&lt;p&gt;Cleanup isn&amp;rsquo;t easy. I know this from having needed to delete or update data in various circumstances over the years &amp;ndash; it&amp;rsquo;s tough to clean things up safely without impacting performance.&lt;/p&gt;
&lt;p&gt;Query Store has some issues with this currently as well.&lt;/p&gt;
&lt;p&gt;If you collect wait stats in Query Store, Query Store size-based cleanup of wait stats runs a query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_persist_wait_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pws&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_persist_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;If you monitor your SQL Server or Azure SQL database from a third party monitoring system like Datadog or Redgate SQL Monitor, you will be able to see this query running in that system. You&amp;rsquo;ll also be able to see it in the plan cache.&lt;/li&gt;
&lt;li&gt;When Query Store has a good amount of data&amp;ndash; but not necessarily enormous (say, 4GB), this query can run repeatedly for a very long time when called by cleanup.&lt;/li&gt;
&lt;li&gt;This query has significant impacts&amp;ndash; more than I would have expected. In an environment with a synchronous availability group in a high activity period, this can depress the rate of transaction log flushes and notably raise the level of HADR_SYNC_COMMIT and HADR_GROUP_COMMIT waits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can produce this behavior/impact in a test environment with a synchronous Availability Group setup using Ostress.exe, after first building up a volume of data in Query Store.&lt;/p&gt;
&lt;p&gt;I have not been able to produce similar impacts from other parts of Query Store cleanup, only wait stats cleanup, but it might be that they exist and my testing simply didn&amp;rsquo;t uncover them. Better safe than sorry.&lt;/p&gt;
&lt;h2 id="when-to-consider-not-collecting-wait-stats-in-query-store"&gt;When to Consider Not Collecting Wait Stats in Query Store&lt;/h2&gt;
&lt;p&gt;If you have a performance critical database and you want to ensure this doesn&amp;rsquo;t happen, you don&amp;rsquo;t have to collect wait statistics in Query Store.&lt;/p&gt;
&lt;p&gt;I find the wait stats in Query Store to be occasionally useful only. They are aggregate wait stats, so they can give a general idea for simple issues like whether or not a query often waits on lock waits, but they aren&amp;rsquo;t super granular. If you do have an external monitoring system that is collecting wait stats, and if it allows you to correlate those wait stats to queries, you might simply decide not to collect wait stats in Query Store.&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modifying settings in Query Store will clear your execution plan cache, so don&amp;rsquo;t do this at a peak time if that&amp;rsquo;s an issue for you.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;ve been collecting wait stats in Query Store and you disable collection, it does not immediately truncate the wait stats. Cleanup will still need to take care of them, unless you clear Query Store.
&lt;ul&gt;
&lt;li&gt;Obviously, that will cause you to lose Query Store data. You might mitigate this by restoring a backup of the database to access that data if you need it, or you might be willing to start with a clean Query Store, up to you.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="size-based-cleanup---avoid-this"&gt;Size Based Cleanup - Avoid This&lt;/h2&gt;
&lt;p&gt;Query Store has two types of cleanup: time based and size based.&lt;/p&gt;
&lt;p&gt;If performance is critical, you should tune your query store so that only time-based cleanup runs.&lt;/p&gt;
&lt;p&gt;Things to know about size based cleanup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is based on MAX_STORAGE_SIZE_MB when SIZE_BASED_CLEANUP_MODE is set to AUTO. &amp;ldquo;Size-based cleanup will be automatically activated when size on disk reaches 90 percent of max_storage_size_mb. This is the default configuration value. Size-based cleanup removes the least expensive and oldest queries first. It stops when approximately 80 percent of max_storage_size_mb is reached.&amp;rdquo; &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-query-store-options-transact-sql?view=sql-server-ver16"&gt;Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re working to reproduce issues with sized based issues, you may hit scenarios where your Query Store goes into read-only mode before cleanup starts. I found that I could avoid this by doing a little dance: I ran a workload to grow Query Store to 90% of MAX_STORAGE_SIZE_MB. Then I stopped my workload briefly (cleanup seems to need a lull) and ran sp_query_store_flush_db. Then I started my stress test again immediately. The timing is a bit delicate, but this allowed me to run a test load at the same time size-based cleanup was running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may want to allow Query Store some more room in MAX_STORAGE_SIZE_MB so that sized-based cleanup doesn&amp;rsquo;t kick in. Be aware that you shouldn&amp;rsquo;t go completely wild with this &amp;ndash; as the fantastic Erin Stellato mentions in &lt;a href="https://www.sqlskills.com/blogs/erin/query-store-best-practices/"&gt;Query Store Best Practices&lt;/a&gt;: MAX_STORAGE_SIZE_MB should be &amp;ldquo;set to 10GB at the absolute max, something less ideally&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Erin recommends a custom capture policy to help if you need to reduce the amount of space that Query Store data takes up.&lt;/p&gt;
&lt;p&gt;Erin mentions in &lt;a href="https://www.sqlskills.com/blogs/erin/remove-data-from-query-store/"&gt;Remove Data from Query Store&lt;/a&gt; that&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ideally, size-based cleanup never kicks in&amp;hellip;. This algorithm is not efficient, and it runs single-threaded. It looks for queries that are infrequently executed/less important and deletes those, one by one, until the size is less than 80% of MAX_STORAGE_SIZE_MB. Avoid this type of cleanup if at all possible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My testing shows this to be very good advice.&lt;/p&gt;
&lt;p&gt;To monitor size based cleanup, you can trace the &lt;code&gt;query_store_size_retention_cleanup_started&lt;/code&gt; and &lt;code&gt;query_store_size_retention_cleanup_finished&lt;/code&gt; Extended Events. Read more in Zikato&amp;rsquo;s answer on &lt;a href="https://dba.stackexchange.com/questions/331117/what-is-execution-count-in-query-store/331156#331156"&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-mysteries-of-time-based-cleanup"&gt;The Mysteries of Time Based Cleanup&lt;/h2&gt;
&lt;p&gt;Josh Darnell has written an excellent post on &lt;a href="https://joshthecoder.com/2018/12/06/timing-of-automatic-query-store-purge.html"&gt;Timing of the Automatic Query Store Purge&lt;/a&gt;. I won&amp;rsquo;t rehash his whole post here&amp;ndash; go read it!&lt;/p&gt;
&lt;p&gt;The most important basic bits are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time based cleanup happens every 24 hours&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s roughly based on startup time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means that if you happen to have a failover in the middle of the day, you may end up with time-based cleanup running in the middle of the day. Not ideal. Depending on your tolerance of cleanup running at a high volume time, this might be worth a planned failover at a low volume time.&lt;/p&gt;
&lt;p&gt;As much as I don&amp;rsquo;t love that, I still find Query Store to be useful enough in general to deal with that.&lt;/p&gt;
&lt;p&gt;To monitor time based cleanup, you can trace two Extended Events: &lt;code&gt;query_store_db_cleanup__started&lt;/code&gt; and &lt;code&gt;query_store_db_cleanup__finished&lt;/code&gt;. Only time-based cleanup events are captured in these events.&lt;/p&gt;
&lt;h2 id="diy-cleanup"&gt;DIY Cleanup&lt;/h2&gt;
&lt;p&gt;There are a few stored procedures you can do to add custom cleanup jobs to run on schedule if you like. &lt;a href="https://www.sqlskills.com/blogs/erin/remove-data-from-query-store/"&gt;Erin Stellato give examples of them in &amp;lsquo;Remove Data from Query Store&amp;rsquo;&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_remove_query&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ZZZ&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_remove_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;YYY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_reset_exec_stats&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;YYY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="product-improvements-that-would-help"&gt;Product Improvements That would Help&lt;/h2&gt;
&lt;p&gt;The following things would be super helpful:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Allow configuration of when time-based cleanup runs&lt;/li&gt;
&lt;li&gt;Give more insight into which bits of Query Store are taking up space and what levers to configure to &amp;ldquo;fit&amp;rdquo; Query Store into your desired maximum size.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And one correction&amp;hellip;
I had suggested:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Increase visibility of when size-based cleanup runs. I would really prefer for this to be logged in a DMV rather than an extended event, as that&amp;rsquo;s easier to get into monitoring systems, but I&amp;rsquo;ll take whatever I can get.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Update: this already exists as an Extended Event. See Zikato&amp;rsquo;s answer on using &lt;code&gt;query_store_size_retention_cleanup_started&lt;/code&gt; and &lt;code&gt;query_store_size_retention_cleanup_finished&lt;/code&gt; on &lt;a href="https://dba.stackexchange.com/questions/331117/what-is-execution-count-in-query-store/331156#331156"&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy performance tuning, and please remember to tip your Query Store (by not allowing size-based cleanup to run).&lt;/p&gt;
&lt;h2 id="thanks-very-much-to-erin-stellato-josh-darnell-and-tomáš-zíka"&gt;Thanks Very Much to Erin Stellato, Josh Darnell, and Tomáš Zíka&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/erinstellato/"&gt;Erin&lt;/a&gt; is super helpful, so smart, and just one of the best folks around. All of her posts on Query Store are incredibly helpful, just search &amp;ldquo;Erin Stellato Query Store&amp;rdquo; when you have a question :) If you work with Erin, please tell her that her awesomeness is widely loved.&lt;/p&gt;
&lt;p&gt;Thanks also to Josh Darnell for his excellent posts on &lt;a href="https://joshthecoder.com/2018/12/06/timing-of-automatic-query-store-purge.html"&gt;Query Store Cleanup&lt;/a&gt;. This was also super helpful to me. And thanks to Tomáš Zíka (Zikato) for his answer detailing how to trace size-based cleanup.&lt;/p&gt;</description></item><item><title>Top 5 Toxic Flavors of Tech Execs</title><link>https://kendralittle.com/2024/04/11/top-5-toxic-flavors-of-tech-execs/</link><pubDate>Thu, 11 Apr 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/04/11/top-5-toxic-flavors-of-tech-execs/</guid><description>&lt;p&gt;I&amp;rsquo;ve been an employee at small, medium, and large companies, and I&amp;rsquo;ve also been a short-term consultant working with a new company in any given week. I&amp;rsquo;ve worked with hundreds of tech companies remotely and have visited companies onsite on multiple continents.&lt;/p&gt;
&lt;p&gt;Air-dropping into company cultures to work through problems with teams and present recommendations to their leadership reveals common anti-patterns in leadership &amp;ndash; plus some patterns that make teams raving fans of their management.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the top 5 Toxic Flavors of Tech Execs I&amp;rsquo;ve encountered over 20 years, plus the Top 5 Team Building Tech Execs I&amp;rsquo;ve found, too.&lt;/p&gt;
&lt;h2 id="five-toxic-flavors-of-tech-execs"&gt;Five Toxic Flavors of Tech Execs&lt;/h2&gt;
&lt;p&gt;As a consultant, teams have sometimes brought me in to help them make headway with these styles of leaders. It&amp;rsquo;s not that I have magical powers, it&amp;rsquo;s simply that when you bring in an outside expert on a topic, often a leader will listen to their voice differently. And short term consultants have an easier time speaking truth to power&amp;ndash; they&amp;rsquo;ve got much less at risk than long term employees.&lt;/p&gt;
&lt;h3 id="5-the-clumsy-penny-pincher"&gt;5. The Clumsy Penny Pincher&lt;/h3&gt;
&lt;p&gt;These execs are highly focused on reducing cost and increasing efficiency, but they&amp;rsquo;re also short sighted. They may not carefully consider the contracts they sign, so they get the worst end of the deal. Their teams struggle with a pile of perverse incentives &amp;ndash; like having a service desk whose success metrics are based on closing tickets, but not actually resolving problems. Cost reduction &lt;em&gt;can&lt;/em&gt; go well, but it can also bring productivity to a grinding halt. It&amp;rsquo;s tricky to make recommendations that anyone will have time to carry out: scope, scope, scope.
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/UnlimitedWaffles.png" width="300"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id="4-the-auto-responder"&gt;4. The Auto-Responder&lt;/h3&gt;
&lt;p&gt;These leaders have an established way of handling difficult conversations: they shut it down with a favorite catch phrase. They use the catch phrase enough to start a meme. Catch phrases are risky when they replace exploring problems: they communicate that the leader isn&amp;rsquo;t willing or able to listen. It is what it is. There&amp;rsquo;s no need to reinvent the wheel. Let&amp;rsquo;s just move forward. We need to think more positively. Let&amp;rsquo;s put a pin in this and move on.&lt;/p&gt;
&lt;h3 id="3-unlimited-waffles"&gt;3. Unlimited Waffles&lt;/h3&gt;
&lt;p&gt;&amp;ldquo;We had too many Priority 1&amp;rsquo;s so we created Priority 0. Now we have too many Priority 0&amp;rsquo;s.&amp;rdquo; Every day is a new adventure with these leaders, either chasing a new rainbow or running from yesterday&amp;rsquo;s nightmare. Just like Groundhog Day, you don&amp;rsquo;t make it far before starting over. It&amp;rsquo;s tricky to make improvements in this org because you can only plan for incredibly short cycles, as few things get momentum to last longer than a few weeks. If you&amp;rsquo;re in this team, you&amp;rsquo;ve gotta always think small.&lt;/p&gt;
&lt;h3 id="2-the-hero-worshipper"&gt;2. The Hero Worshipper&lt;/h3&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/YellingBroccoli.png" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;These leaders invented the 10x developer. They celebrate employees who sacrifice their personal lives. But they only celebrate a hero briefly, then they&amp;rsquo;re on to their next best friend. This leader creates teams who are willing to (or need to) suffer loss of sleep and be absent from their families and friends for the sake of visa support or salary. Collaboration isn&amp;rsquo;t really a thing around the hero worshipper. Most people are stressed, all the time. Short term consultants can be temporarily effective here as they can break up the established dynamic, but it&amp;rsquo;s hard to create lasting change.&lt;/p&gt;
&lt;h3 id="1-the-really-angry-one"&gt;1. The Really Angry One&lt;/h3&gt;
&lt;p&gt;We still have folks in tech who lead with overt displays of power. These senior leaders humiliate and dress down employees in medium and large meetings, and often don&amp;rsquo;t allow the employee to respond or speak further. That employee sometimes disappears in a few days; no announcement is made for their departure. At other times, these execs may be warm and effusive, but they&amp;rsquo;re mercurial. Few leaders intend to be perceived this way; most agree it&amp;rsquo;s better to be loved than feared. But some gamble that it&amp;rsquo;s better to be feared than hated. Some panic often and express that in displays of power. This is the environment which is toughest to make a positive impact in: a command-and-control culture laced with fear is quite resistant to change.&lt;/p&gt;
&lt;h2 id="my-top-5-team-building-tech-execs"&gt;My Top 5 Team Building Tech Execs&lt;/h2&gt;
&lt;p&gt;Leading organizations is a big challenge, I&amp;rsquo;m not saying otherwise. I am in awe of people who are great managers and executives in tech. They do exist, in both large and small companies.&lt;/p&gt;
&lt;p&gt;Here are my favorite Talented Leader Types:&lt;/p&gt;
&lt;h3 id="5-the-agile-nerd"&gt;5. The Agile Nerd&lt;/h3&gt;
&lt;p&gt;Some of y&amp;rsquo;all will read this title and think &amp;ldquo;no no no, that&amp;rsquo;s an anti-pattern! The Agile-Will-Fix-Everything-Type goes on the other list!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The leader I&amp;rsquo;m talking about here isn&amp;rsquo;t the Quick-Fix type. This is the leader who is deeply interested in finding ways of working that are flexible and which empower teams to do their best work with a customer-centric approach. They are open to criticism, love iterative improvement, and they find joy in learning from everyone. This is often a leader who has a lot of humility, but rarely speaks about humility. They are simply mostly interested in learning, growing, and improving their teams and themselves.&lt;/p&gt;
&lt;h3 id="4-the-curious-pragmatist"&gt;4. The Curious Pragmatist&lt;/h3&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/ListeningCarrot.png" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;This leader brings a genuine curiosity to work. They are curious about technical problems and they are also curious about people. This curiosity is paired with pragmatism: they are curious and open to change, but they also focus on how to carry through important projects and maintain &amp;ldquo;stable-enough&amp;rdquo; priorities and room for employees to grow and change over time. This leader has the ability to share the larger organizational context with their teams in a way that encourages innovation, and they are also excellent at advocating upwards for their teams.&lt;/p&gt;
&lt;h3 id="3-the-deep-listener"&gt;3. The Deep Listener&lt;/h3&gt;
&lt;p&gt;Some leaders have a strong willingness and desire to practice listening. They practice this with both senior and junior employees. They don&amp;rsquo;t always try to offer solutions to problems, but they don&amp;rsquo;t brush off problems, either. They have a way of connecting to people and building bonds and trust. They think a lot before they ask questions or make suggestions, and they listen and pay attention to how those questions are answered, and if they create discomfort. When these leaders find the right organization and team that matches their skills, employees express themselves more openly in both small and large groups, and people enjoy problem-solving together. Thoughtfulness has a way of spreading, and these are fun teams to work in.&lt;/p&gt;
&lt;h3 id="2-the-one-whos-been-there"&gt;2. The One Who&amp;rsquo;s Been There&lt;/h3&gt;
&lt;p&gt;Some leaders have strong empathy through years of experience working in the same roles in which their employees work. These folks often don&amp;rsquo;t have a fancy degree, or a college degree at all. They started small, and they still empathize and identify with the employees in the company who have the least amount of power. These leaders are effective at getting things done and are good at finding a middle ground without alienating people. They are often not a &amp;ldquo;big name&amp;rdquo; at work, but they are broadly respected. They have a calming presence, they are very easy for a wide variety of people to feel comfortable talking with, and they often have minimal turnover in their teams. When they move roles, their employees want to follow them.
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/ForceMultiplierBanana.png" width="300"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id="1-the-force-multiplier"&gt;1. The Force Multiplier&lt;/h3&gt;
&lt;p&gt;My favorite leadership style is the leader whose superpower is &lt;em&gt;finding&lt;/em&gt; the superpower in their own employees and teams. This leader isn&amp;rsquo;t afraid of giving feedback, but they don&amp;rsquo;t focus on finding criticism. Instead, they reframe situations and identify how the strengths in their teams can be used to their best advantage. They are talented at thinking of ways to maximize those strengths and leverage uniqueness. These execs recognize potential where others don&amp;rsquo;t. These folks change lives.&lt;/p&gt;
&lt;h2 id="im-generalizing"&gt;I&amp;rsquo;m Generalizing&lt;/h2&gt;
&lt;p&gt;Leaders are people, too. I&amp;rsquo;m not going to go full &amp;ldquo;won&amp;rsquo;t someone sympathize with the CEO who laid thousands of people off,&amp;rdquo; but being a good leader takes practice, thoughtfulness, and dedication over time. Nobody is 100% a &amp;ldquo;bad&amp;rdquo; or &amp;ldquo;good&amp;rdquo; leader. Great leaders have made plenty of mistakes, learned from them, and improved, just like great individual contributors. I&amp;rsquo;m no expert at this&amp;ndash; it&amp;rsquo;s easier said than done&amp;ndash; but I am inspired by the great leaders I&amp;rsquo;ve worked with and I learn more every day. The anti-pattern archetypes that we all know well make good leadership even more important.&lt;/p&gt;</description></item><item><title>Something Weird Happened: I Love My Job Again</title><link>https://kendralittle.com/2024/03/26/something-weird-happened-i-love-my-job-again/</link><pubDate>Tue, 26 Mar 2024 08:32:04 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/03/26/something-weird-happened-i-love-my-job-again/</guid><description>&lt;p&gt;Back in my 20&amp;rsquo;s, I was lucky enough to go to graduate school. I had a work-study job in the Dean&amp;rsquo;s office where I got to develop and administer their Access databases, which helped me get by.&lt;/p&gt;
&lt;p&gt;One day, the Dean said to me: &amp;lsquo;Kendra, when you talk about your work on our databases, you light up. When you talk about your coursework, that doesn&amp;rsquo;t happen. Have you thought about that?&amp;rsquo;&lt;/p&gt;
&lt;p&gt;That observation changed my life.&lt;/p&gt;
&lt;!--more --&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Kendra-Little-Self-Portrait.png" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;I finished up my Master&amp;rsquo;s degree and left graduate school. I got my first job in tech. I couldn&amp;rsquo;t land a job specializing in databases right away, but I kept getting more and more database experience and I eventually landed a job working with SQL Server full time.&lt;/p&gt;
&lt;p&gt;I loved it.&lt;/p&gt;
&lt;h2 id="eventually-i-decided-to-try-other-things"&gt;Eventually, I Decided to Try Other Things&lt;/h2&gt;
&lt;p&gt;After working with databases for more than ten years, I felt like I should try new things. Not completely unrelated things&amp;mdash; I still was very interested in database performance and software development&amp;ndash; but I wanted to explore a bit.&lt;/p&gt;
&lt;p&gt;I tried my hand at being a Developer Advocate, then a Product Manager.&lt;/p&gt;
&lt;p&gt;I worked as a Content Developer, then as a Technical Product Manager for a Data Platform team.&lt;/p&gt;
&lt;p&gt;I was good at these roles, and I learned a ton. As a TPM I worked with a terrific team who taught me a ton about Data Platforms and Data Science, which was fascinating. But for various reasons, I ended up leaving that role and spending a few months thinking about what I wanted to do next. It was tough to find an answer.&lt;/p&gt;
&lt;p&gt;Six months ago, I saw a job listing for a Database Reliability Engineer at &lt;a href="https://dutchie.com/"&gt;Dutchie&lt;/a&gt; that looked&amp;hellip; well it looked amazing. It was a performance tuning role using PAAS databases in the cloud, focusing on SQL Server but with opportunities to also work with Postgres, which I&amp;rsquo;ve wanted to work with for a while.&lt;/p&gt;
&lt;p&gt;I got lucky and landed the job.&lt;/p&gt;
&lt;h2 id="i-ended-up-working-last-sunday"&gt;I Ended Up Working Last Sunday&lt;/h2&gt;
&lt;p&gt;When you do production work with a 24 hour online system, you end up working occasional nights or weekends. (Automation and careful system design can lessen this a lot, but sometimes it&amp;rsquo;s just easier and faster to do something at a low volume time. And I could take Monday off.)&lt;/p&gt;
&lt;p&gt;At one point on Sunday, my partner looked in my doorway and smiled. I don&amp;rsquo;t know what I was doing, probably laughing at the query optimizer&amp;rsquo;s choices. I had no idea it would sometimes use a key lookup in an index creation statement.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;You&amp;rsquo;re SO happy,&amp;rdquo; he said. &amp;ldquo;I love that you&amp;rsquo;re so happy now.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Yeah, I was happy working on a weekend. Working with relational databases is what lights me up, after all these years.&lt;/p&gt;
&lt;p&gt;I am still that kid learning the lesson that there&amp;rsquo;s something about databases which my brain can&amp;rsquo;t get enough of.&lt;/p&gt;</description></item><item><title>You Will Not Find Long Compilers Who Time Out in Query Store</title><link>https://kendralittle.com/2024/03/05/long-compilers-who-time-out-not-in-query-store/</link><pubDate>Tue, 05 Mar 2024 08:40:57 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/03/05/long-compilers-who-time-out-not-in-query-store/</guid><description>&lt;p&gt;Last November, a puzzle was really bothering me. Some queries from an application were timing out frequently after running for 30 seconds, but they were halfway invisible in the SQL Server.&lt;/p&gt;
&lt;p&gt;I say &amp;lsquo;halfway invisible&amp;rsquo; because I could see the queries while they were running in SQL Server&amp;rsquo;s dynamic management views using free tools (&lt;a href="https://github.com/amachanic/sp_whoisactive"&gt;sp_WhoIsActive&lt;/a&gt; and &lt;a href="https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/blob/dev/sp_BlitzWho.sql"&gt;sp_BlitzWho&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;But the queries had some odd characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They had a sql_handle, but never a query_hash&lt;/li&gt;
&lt;li&gt;They also never showed a plan_hash or execution plan&lt;/li&gt;
&lt;li&gt;I couldn&amp;rsquo;t &lt;a href="https://kendralittle.com/2022/03/11/find-execution-timeouts-query-store/"&gt;find the timeouts in Query Store like a normal timeout&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/img/free-sql-comics/query-store-i-dont-know-her.png" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="query-store-wont-see-a-query-that-doesnt-finish-compiling"&gt;Query Store Won&amp;rsquo;t See a Query That Doesn&amp;rsquo;t Finish Compiling&lt;/h2&gt;
&lt;p&gt;This all happened around the time of the &lt;a href="https://passdatacommunitysummit.com/"&gt;PASS Data Community Summit&lt;/a&gt; in Seattle. I thought, surely if I ask enough people, someone will have an idea that sticks.&lt;/p&gt;
&lt;p&gt;I ended up in the Expo Hall, babbling about half invisible queries to anyone who would listen. This was actually a good strategy.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt; and a group of fine Microsoft PMs listened to my tale of confusion. Erik suggested, &amp;ldquo;Maybe the query isn&amp;rsquo;t done compiling?&amp;rdquo; &lt;a href="http://erinstellato.com/about/"&gt;Erin Stellato&lt;/a&gt; thought it through and confirmed that yes, if the query did not finish the compilation process before the client cancelled it, then that run of the query wouldn&amp;rsquo;t be recorded in Query Store.&lt;/p&gt;
&lt;p&gt;(After this chat, I eventually found and read the Learn article on &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/how-query-store-collects-data?view=sql-server-ver16#query-processing"&gt;How Query Store Collects Data&lt;/a&gt;, which gives more detail on Query Store and how it fits into query processing. Read that to learn more, it&amp;rsquo;s good.)&lt;/p&gt;
&lt;h2 id="identifying-a-long-compiler"&gt;Identifying a Long Compiler&lt;/h2&gt;
&lt;p&gt;Before this, I hadn&amp;rsquo;t really thought about how a query appears in SQL Server DMVs if it is still compiling. I&amp;rsquo;d taken short compile times for granted. It turns out I shouldn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;As I mentioned above, some traits of a query in the compilation phase are that you&amp;rsquo;ll see a sql_handle, but not a query hash, query plan, or query plan hash.&lt;/p&gt;
&lt;p&gt;There is another way you can monitor these and confirm that a query is compiling as well: you can query &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-active-transactions-transact-sql"&gt;sys.dm_tran_active_transactions&lt;/a&gt; for transactions where the &lt;strong&gt;name&lt;/strong&gt; column has the value &lt;code&gt;sqlsource_transform&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;transaction_begin_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_begin_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SECOND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_begin_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYSDATETIME&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_tran_active_transactions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sqlsource_transform&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thanks to the &lt;a href="https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/performance/troubleshoot-never-ending-query#long-compilation-time"&gt;Troubleshoot queries that seem to never end in SQL Server&lt;/a&gt; article for this little tip, it helped me confirm that I was, in fact, seeing queries that were taking longer than 30 seconds to compile, and being cancelled due to a timeout before they ever got a query plan.&lt;/p&gt;
&lt;p&gt;Why were they compiling so long? I&amp;rsquo;ve got some details, but some of it is still mysterious. Stay tuned for more in a future post.&lt;/p&gt;
&lt;p&gt;And many thanks to &lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt;, &lt;a href="http://erinstellato.com/about/"&gt;Erin Stellato&lt;/a&gt;, and others for their invaluable help and advice.&lt;/p&gt;</description></item><item><title>How to Start an XEvents Trace on a Read Scale-Out Azure SQL Managed Instance</title><link>https://kendralittle.com/2024/02/29/xevents-trace-azure-sql-managed-instance-read-scale-out/</link><pubDate>Thu, 29 Feb 2024 08:21:15 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/02/29/xevents-trace-azure-sql-managed-instance-read-scale-out/</guid><description>&lt;p&gt;It took me more than half hour to figure out how to start an XEvents trace on a read-scale out instance of Azure SQL Managed Instance. It&amp;rsquo;s hard to monitor read scale-out instances, so tracing is desirable! I started with a simple trace of &lt;code&gt;sql_statement_completed&lt;/code&gt;. Hopefully this saves other folks some time.&lt;/p&gt;
&lt;h2 id="architecture-review-what-are-read-scale-out-instances-in-managed-instance"&gt;Architecture Review: What are Read Scale-out Instances in Managed Instance?&lt;/h2&gt;
&lt;p&gt;Read scale-out instances are provided when you use the Business Critical tier for Azure SQL Managed Instance. These use an availability-groups like technology to keep databases fresh in a read-only format.&lt;/p&gt;
&lt;p&gt;You can offload queries to this read-only replica with near realtime data. However, the instances are tricky to monitor: most 3rd party monitoring systems have no idea what these are, and they don&amp;rsquo;t emit performance counters like a &amp;rsquo;normal&amp;rsquo; instance.&lt;/p&gt;
&lt;p&gt;If you have configured a Failover Group and the failover partner is in the Business Critical service tier, that partner will also have read scale-out instances.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureSQLManagedInstance-BusinessCritical-HA-Architecture.gif"&gt;
&lt;/figure&gt;
&lt;h2 id="want-to-use-an-event-file-target-buckle-up"&gt;Want to Use an Event File Target? Buckle Up&lt;/h2&gt;
&lt;p&gt;I typically like to create both an event file target and a ring buffer target if the trace may run for a while.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a few steps to set up a Managed Instance to work with event file targets. You can reuse this configuration for multiple XEvents traces, if that&amp;rsquo;s a comfort.&lt;/p&gt;
&lt;p&gt;Follow the steps in &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/xevent-code-event-file"&gt;Create an event session with an event_file target in Azure Storage&lt;/a&gt; to do the following in the Azure Portal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify or create the Azure Storage Account you want to use&lt;/li&gt;
&lt;li&gt;Create a container/bucket in the storage account where your trace files will be written&lt;/li&gt;
&lt;li&gt;Create a SAS token for the container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After this, the article instructs you to run a TSQL command against your Managed Instance to store the SAS token in a server-scoped credential.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where to run this step&lt;/strong&gt;: The Managed Instance which is the &amp;ldquo;base&amp;rdquo; of the read scale-out instance. This might be your primary writable replica, or it might be the failover partner, or it might be both. (It is NOT the read scale-out instance. Connect with ApplicationIntent=ReadWrite.)&lt;/p&gt;
&lt;p&gt;If you aren&amp;rsquo;t sure if this may have been done before, check if a credential has been set up in your Managed Instance with the following query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The credential name will be something like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://exampleaccount4xe.blob.core.windows.net/xe-example-container"&gt;https://exampleaccount4xe.blob.core.windows.net/xe-example-container&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The identity will be &lt;code&gt;SHARED ACCESS SIGNATURE&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="create-the-trace-definition-on-the-primary-replica-or-failover-partner--ssms-will-get-you-halfway-there"&gt;Create the Trace Definition on the Primary Replica or Failover Partner &amp;ndash; Ssms will Get You Halfway There&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Where to run this step&lt;/strong&gt;: The Managed Instance which is the &amp;ldquo;base&amp;rdquo; of the read scale-out instance. This might be your primary writable replica, or it might be the failover partner, or it might be both. (It is NOT the read scale-out instance. Connect with ApplicationIntent=ReadWrite.)&lt;/p&gt;
&lt;p&gt;SQL Server Management Studio (SSMS) only partially supports creating XEvents sessions. You can &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/xevent-code-event-file?view=azuresql&amp;amp;tabs=sqldb#create-start-and-stop-an-event-session"&gt;use the built in wizard to configure the session&lt;/a&gt;, but when you go to configure where to write the event file target it will thing the url for the location is an error.&lt;/p&gt;
&lt;p&gt;So you need to script out the definition to TSQL, put the URL into the TSQL, and execute it in SQL to create the XEvents trace.&lt;/p&gt;
&lt;p&gt;Is this a stack of workarounds in a trench coat? Absolutely.&lt;/p&gt;
&lt;h2 id="make-sure-the-trace-definition-syncs-to-the-read-scale-out"&gt;Make Sure the Trace Definition Syncs to the Read Scale-out&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/raccoon-building-rube-goldberg.png" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;Your trace now should exist on the Managed Instance where you created it (a primary replica or a failover partner).&lt;/p&gt;
&lt;p&gt;If you now connect to your read scale-out instance (&lt;code&gt;ApplicationIntent=READONLY&lt;/code&gt;), you should see in Object Explorer that the definition has synced over.&lt;/p&gt;
&lt;p&gt;I had to open a second instance of SSMS to get Object Explorer to have connections to both an instance and its read scale-out partner at the same time.&lt;/p&gt;
&lt;h2 id="start-the-trace-on-the-primary-replica-or-failover-partner-then-on-the-read-scale-out-instance"&gt;Start the Trace on the Primary Replica or Failover Partner, Then on the Read Scale-out Instance&lt;/h2&gt;
&lt;p&gt;At the time I wrote this, the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/read-scale-out?view=azuresql#monitor-read-only-replicas-with-extended-events"&gt;documentation&lt;/a&gt; claimed:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An extended event session on a read-only replica that is based on a session definition from the primary replica can be started and stopped independently of the session on the primary replica.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn&amp;rsquo;t find that to be true. If I attempted to start the XEvents trace on the read scale-out replica at this point, I got the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 3906, Level 16, State 2, Line 1
Failed to update database &amp;#34;master&amp;#34; because the database is read-only.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In order to get the trace started on the read scale-out instance, I had to do a little dance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start the trace on the primary replica or failover partner&lt;/li&gt;
&lt;li&gt;Start the trace on the read scale-out partner&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I put in a PR to update the docs, so hopefully someone verifies this and figures out if it&amp;rsquo;s the same or different for Azure SQL Database.&lt;/p&gt;
&lt;h2 id="stop-the-trace-on-the-primary-replica-or-failover-partner"&gt;Stop the Trace on the Primary Replica or Failover Partner&lt;/h2&gt;
&lt;p&gt;If you don&amp;rsquo;t need the trace to run on the primary replica or failover partner, you can stop it there. But don&amp;rsquo;t drop it&amp;ndash; you need to leave it there as long as you want to run it on the read scale-out instance.&lt;/p&gt;
&lt;p&gt;Hopefully nobody comes along and cleans it up.&lt;/p&gt;
&lt;h2 id="verify-your-trace-is-working"&gt;Verify Your Trace is Working&lt;/h2&gt;
&lt;p&gt;Is it writing to the targets and picking up data? After all this, I sure hope so.&lt;/p&gt;
&lt;p&gt;The good news is that you can now open the results of event-file traces inside SSMS, like a normal XEvents trace. This is&lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/improving-extended-events-in-azure-sql/ba-p/3980918"&gt;a recent improvement which is VERY nice&lt;/a&gt;&amp;ndash; you used to have to download the files from Azure Storage, which required stopping a trace and other bother. It&amp;rsquo;s much more convenient to work with trace data in SSMS now for Azure SQL Managed Instance.&lt;/p&gt;</description></item><item><title>Should You Use SQL Server Readable Secondaries If Queries Can Fail Repeatedly at Any Time?</title><link>https://kendralittle.com/2024/02/21/queries-against-readable-availability-group-secondaries-may-fail-repeatedly-until-you-intervene/</link><pubDate>Wed, 21 Feb 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/02/21/queries-against-readable-availability-group-secondaries-may-fail-repeatedly-until-you-intervene/</guid><description>&lt;p&gt;If you use readable secondaries in Availability Groups or Read-Scale out instances in Azure SQL Managed Instance, you may have queries fail repeatedly if there is a glitch and statistics are not successfully &amp;lsquo;refreshed&amp;rsquo; on the secondary replica. Those queries may keep failing until you manually intervene.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s unclear if Microsoft will ever fix this. There is a well established &lt;a href="https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/availability-groups/error-2767-query-secondary-replica-fails"&gt;support deflection article&lt;/a&gt; which documents the issue and provides &amp;lsquo;workarounds&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;As a user on StackExchange &lt;a href="https://dba.stackexchange.com/a/275258/471"&gt;wrote in September of 2022&lt;/a&gt;, &amp;ldquo;This is an outstanding bug in SQL Server which has been ignored for quite some time, unfortunately.&amp;rdquo; Based on a link provided in that post, it appears feedback was provided for this as far back as SQL Server 2012, when AGs were introduced.&lt;/p&gt;
&lt;p&gt;More than 12 years later, how viable are readable secondaries / scale-out read servers for production use if it&amp;rsquo;s acceptable for queries to fail at an undocumented/unknown rate?&lt;/p&gt;
&lt;h2 id="what-causes-statistics-not-to-refresh-on-a-secondary-can-you-prevent-it"&gt;What Causes Statistics Not to Refresh on a Secondary? can You Prevent It?&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not really clear to me what causes this error. Microsoft&amp;rsquo;s &lt;a href="https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/availability-groups/error-2767-query-secondary-replica-fails"&gt;support deflection article&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This issue occurs because an active transaction prevents the cache invalidation log record from accessing and refreshing the statistics on the secondary replica.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I ran into this issue, there were no long-running transactions on the primary replica or any secondary replicas. Potentially this had happened at some point in the past and the process that refreshes statistics gave up, or was a victim in a deadlock and didn&amp;rsquo;t retry? All I have is guesses.&lt;/p&gt;
&lt;h2 id="the-workarounds-suck-here-folks"&gt;The Workarounds Suck Here, Folks&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/prod-database-or-easy-bake.png"
alt="Illustration comparing a production database to an Easy Bake Oven" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;If this issue happens to you, the article presents three options for workarounds:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Dump all of the caches on the secondary replica&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I don&amp;rsquo;t love this step as a fix for a production database server. It&amp;rsquo;s fine on some workloads, but there are plenty where it causes performance issues. The article also indicates that this is not as &amp;ldquo;permanent&amp;rdquo; an option as option 3, too.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Fail the node over&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;OK, so this option is to take a brief outage on the server? Really? How is this option 2? Is this a production database or an Easy Bake Oven?&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Manually delete the statistic on the primary and recreate it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I guess I choose this as the &amp;ldquo;least worst&amp;rdquo; option. For undisclosed reasons, this is labeled a &amp;ldquo;more permanent workaround.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Do I want to automate proactively finding this issue if it happens and repairing it? No.&lt;/p&gt;
&lt;h2 id="does-microsoft-know-how-often-this-happens"&gt;Does Microsoft Know How Often This Happens?&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t think Microsoft understands how often this happens.&lt;/p&gt;
&lt;p&gt;First, the article linked above is intended to drive down support requests. This saves money for Microsoft, and frankly users appreciate it because none of us want to work through support tickets, however it means that Microsoft doesn&amp;rsquo;t get signals about how many people are hitting the problem.&lt;/p&gt;
&lt;p&gt;I can say that this does still happen with the latest versions of SQL Server and that it occurs on Azure SQL Managed Instance, based on what I have seen and what I see others reporting in &lt;a href="https://mohammaddarab.com/could-not-locate-statistics-in-the-system-catalogs-of-secondary-replica/"&gt;blogs&lt;/a&gt; and forum posts. The support article also references Azure SQL Database, so presumably it happens there as well.&lt;/p&gt;
&lt;h2 id="whats-up-with-the-mention-of-sp_table_statistics2_rowset"&gt;What&amp;rsquo;s Up with the Mention of Sp_table_statistics2_rowset?&lt;/h2&gt;
&lt;p&gt;In Microsoft&amp;rsquo;s support deflection article, the full sample error is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 2767, Level 16, State 1, Procedure sp_table_statistics2_rowset, Line &lt;LineNumber&gt; [Batch Start Line &lt;LineNumber&gt;]
Could not locate statistics &amp;lsquo;&lt;StatisticsName&gt;&amp;rsquo; in the system catalogs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;strong&gt;sp_table_statistics2_rowset&lt;/strong&gt; system procedure is not fully documented. This procedure is run automatically when you use a linked server to run a query, but the article doesn&amp;rsquo;t mention linked servers at all or say that the bug only occurs when using a linked server.&lt;/p&gt;
&lt;p&gt;Since the article explains that a statistic is not present/not usable on the secondary replica itself, presumably this &lt;em&gt;can&lt;/em&gt; impact queries running without linked servers, but it&amp;rsquo;s not clear to me if they fail or if they just ignore the statistic (and maybe get a worse plan). I have seen that a query may fail due to this when run with a linked server, but the same query may run successfully if run against the replica correctly &amp;ndash; more on that in an upcoming post.&lt;/p&gt;
&lt;h2 id="can-you-rely-on-an-architecture-on-readable-secondaries-with-sql-server--scale-out-read-instances-with-azure-sql-managed-instance"&gt;Can You Rely on an Architecture on Readable Secondaries with SQL Server / Scale-out Read Instances with Azure SQL Managed Instance?&lt;/h2&gt;
&lt;p&gt;Given how long this issue has been around and the level of customer impact it seems to have (queries failing repeatedly with no warning until an administrator intervenes), I think this is an important question worth asking.&lt;/p&gt;
&lt;p&gt;I would love to hear more from Microsoft about this in their blog posts or support articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why is the &amp;ldquo;manual&amp;rdquo; statistics fix &amp;ldquo;more permanent&amp;rdquo;?&lt;/li&gt;
&lt;li&gt;Can this happen with statistics related to indexes?&lt;/li&gt;
&lt;li&gt;What happens when &lt;strong&gt;sp_table_statistics2_rowset&lt;/strong&gt; isn&amp;rsquo;t involved?&lt;/li&gt;
&lt;li&gt;Is it something Microsoft intends to fix eventually? Who needs to complain to make that happen?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As it is, it just seems like &lt;a href="https://www.sqlskills.com/blogs/jonathan/availability-group-readable-secondaries-just-say-no/"&gt;another reason not to use readable secondaries&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Ugly Bug: SQL Server Online Index Rebuild Sometimes Happens Offline Without Warning</title><link>https://kendralittle.com/2024/02/07/sql-server-online-index-rebuild-offline-blocking-outage/</link><pubDate>Wed, 07 Feb 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/02/07/sql-server-online-index-rebuild-offline-blocking-outage/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: This issue has now been documented. A note has been added &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/perform-index-operations-online"&gt;to the Perform index operations online&lt;/a&gt; documentation page, stating: "Index rebuild commands might hold exclusive locks on clustered indexes after a large object column is dropped from a table, even when performed online."
&lt;/div&gt;
&lt;p&gt;I found a nasty bug in SQL Server and Azure SQL Managed Instance recently: sometimes an &amp;lsquo;online&amp;rsquo; index rebuild of a disk-based rowstore clustered index (basically a normal, everyday table) isn&amp;rsquo;t actually &amp;lsquo;online&amp;quot;. In fact, it&amp;rsquo;s very OFFLINE, and it blocks both read and write queries against the table for long periods.&lt;/p&gt;
&lt;p&gt;If you manage to make it through a rebuild successfully, the problem goes away for future rebuilds of that clustered index &amp;ndash; likely leaving you bruised and bewildered.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/online_rebuild_blocking_comic_sql_server.png"&gt;
&lt;/figure&gt;
&lt;h2 id="fine-print-for-the-well-actually-crowd"&gt;Fine Print for the &amp;lsquo;Well Actually&amp;rsquo; Crowd&lt;/h2&gt;
&lt;p&gt;This bug isn&amp;rsquo;t related to the schema modification lock (&lt;code&gt;SCH_M&lt;/code&gt;) taken out briefly at the end of an online index operation. That&amp;rsquo;s documented, and risks of that can be mitigated with the &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; setting. This post describes and has a repro script for exclusive (&lt;code&gt;X&lt;/code&gt;) locks held for long periods through the duration of the supposedly online operation. The &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; setting offers no protection for these locks in my testing. I am also only discussing examples that drop newer types of LOB columns &amp;ndash; my repro script uses &lt;code&gt;NVARCHAR(max)&lt;/code&gt;, and the problem also happens with &lt;code&gt;VARBINARY(max)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="when-does-this-happen"&gt;When does This Happen?&lt;/h2&gt;
&lt;p&gt;I can reproduce this problem when rebuilding a clustered index online after dropping a large object column (LOB) from the table. The problem happens even if &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-cleantable-transact-sql"&gt;DBCC CLEANTABLE&lt;/a&gt; has been run to clean up LOB table from removed columns already.&lt;/p&gt;
&lt;p&gt;What &lt;em&gt;should&lt;/em&gt; happen is that the &lt;code&gt;ALTER INDEX ... REBUILD WITH (ONLINE=ON)&lt;/code&gt; command should return an error if the operation can&amp;rsquo;t be performed online. And there should be a published way to detect or understand when online index operations aren&amp;rsquo;t available. but this isn&amp;rsquo;t the case. Instead, the supposedly &amp;ldquo;online&amp;rdquo; command runs very slowly and takes out exclusive locks. Depending on your environment, that might cause some big old problems.&lt;/p&gt;
&lt;h2 id="if-it-worked-properly-what-would-happen"&gt;If It Worked Properly, What would Happen?&lt;/h2&gt;
&lt;p&gt;This diagram from the &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/how-online-index-operations-work"&gt;How online index operations work&lt;/a&gt; article is helpful in understanding the locks that &lt;em&gt;should&lt;/em&gt; be taken out in an online index operation for a disk based rowstore table:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/online-index-diagram-microsoft.png"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;To reiterate, this is Microsoft&amp;rsquo;s diagram from &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/how-online-index-operations-work"&gt;How online index operations work&lt;/a&gt;, and is not my own work.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Note that there aren&amp;rsquo;t any exclusive (&lt;code&gt;X&lt;/code&gt;) locks in this diagram.&lt;/p&gt;
&lt;h2 id="why-is-this-so-bad"&gt;Why is This So Bad?&lt;/h2&gt;
&lt;p&gt;As Microsoft&amp;rsquo;s &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/perform-index-operations-online"&gt;documentation says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We recommend performing online index operations for business environments that operate 24 hours a day, seven days a week, in which the need for concurrent user activity during index operations is vital.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Online index rebuilds are only available in Expensive editions of SQL Server: Enterprise and Azure SQL. In my personal experience, online index rebuilds are one of the major features that sell licenses for those Expensive editions &amp;ndash; while REORGANIZE commands can be performed online, they are fairly limited and are generally quite slow.&lt;/p&gt;
&lt;p&gt;A bug in a major feature that sells those Expensive licenses is a pretty big deal. It&amp;rsquo;s not uncommon to use large object columns, and it&amp;rsquo;s also not uncommon to want to drop those columns once the data becomes unwieldy.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m quite surprised that this problem &lt;a href="https://dba.stackexchange.com/a/291490/471"&gt;appears to have existed in SQL Server since 2020 and is reported to be a known issue by Microsoft Support since May 2021&lt;/a&gt;. I haven&amp;rsquo;t found this documented by Microsoft. I would expect this limitation to be listed in &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/guidelines-for-online-index-operations"&gt;Guidelines for online index operations&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/perform-index-operations-online"&gt;Perform index operations online&lt;/a&gt;, and &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/how-online-index-operations-work"&gt;How online index operations work&lt;/a&gt;, but I can&amp;rsquo;t find a mention anywhere.&lt;/p&gt;
&lt;p&gt;It is possible that the bug was fixed before and has recurred. Or it&amp;rsquo;s documented someplace I haven&amp;rsquo;t found yet. But it seems like a sad situation.&lt;/p&gt;
&lt;h2 id="this-happens-in-sql-server-2022-azure-sql-managed-instance-and-probably-the-rest-of-the-gang-as-well"&gt;This Happens in SQL Server 2022, Azure SQL Managed Instance, and Probably the Rest of the Gang as Well&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve reproduced this problem in two environments: SQL Server 2022 Developer Edition and Azure SQL Managed Instance. The Stack Exchange post above mentions Azure SQL Database having the problem, but I haven&amp;rsquo;t verified that myself.&lt;/p&gt;
&lt;p&gt;Feel free to use my script below as the basis to check out other versions of SQL Server if you&amp;rsquo;d like.&lt;/p&gt;
&lt;h2 id="does-this-happen-under-x-y-or-z-scenarios"&gt;Does This Happen Under X, Y, or Z Scenarios?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been able to reproduce this problem with the script below. I haven&amp;rsquo;t tested a bunch of variations of the scripts with different table schemas, data types, etc, simply because time is scarce. I&amp;rsquo;m writing this at 9 pm and I still have raccoon drawings to color and shade before the post is done. (Priorities.)&lt;/p&gt;
&lt;p&gt;Basically, this could happen only under the scenario I have described below, or it could also happen under other scenarios as well. Feel free to use the script as a start for your own testing and explore more.&lt;/p&gt;
&lt;h2 id="how-i-reproduced-the-problem-with-screenshots"&gt;How I Reproduced the Problem, with Screenshots&lt;/h2&gt;
&lt;p&gt;Setup: download and install &lt;a href="https://github.com/amachanic/sp_whoisactive"&gt;the free diagnostic stored procedure, sp_WhoIsActive&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, create a little test database if you want. I used compat level 160 because i wanted to use &lt;code&gt;GENERATE_SERIES()&lt;/code&gt; later on. I&amp;rsquo;ve seen this in compat level 150 as well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DropLOBColumnTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DropLOBColumnTest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DropLOBColumnTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;1. Create a table, dbo.LOBTest&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am making a questionable choice and using &lt;code&gt;FILLFACTOR&lt;/code&gt;=1. The bug can absolutely happen with a fillfactor of 100%. I am lazy and I wanted a way to create a bunch of in-row data pages without actually having to calculate a bunch of data to fill them in, so I did that. Follow your heart and change it if you like.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOBTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOBTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;identity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpk_lob&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILLFACTOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;2. Add some data to dbo.LOBTest&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How much data depends on what type of database you are using and how patient you are. On Azure SQL Managed Instance, I used &amp;ldquo;GO 10&amp;rdquo; and could reproduce the issue. On my laptop I went ahead and did 50 rounds because it&amp;rsquo;s much faster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOBTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4001&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GENERATE_SERIES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--GO 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;3. Check how much data is in dbo.LOBTest&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This table is measured by weight, not by volume.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;heap&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;clustered&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TableType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type_desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SizeGB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;Rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partitions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocation_units&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;container_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOBTest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_pages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type_desc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SizeGB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have 7.6GB of LOB data and 3.8GB of in row data.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/LOBTest_table_before_column_drop.png"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;3. Drop one of the LOB columns from dbo.LOBTest&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Goodbye, column k:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOBTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COLUMN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;4. Check how much LOB data you have now (spoiler: it&amp;rsquo;s the same)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Run the query above to check how much data is in the table. You should see the same amount. When you drop a LOB column, the space isn&amp;rsquo;t deallocated.&lt;/p&gt;
&lt;p&gt;There are two ways to get the space back: &lt;code&gt;DBCC CLEANTABLE&lt;/code&gt; or a clustered index rebuild. (I&amp;rsquo;ve tested &lt;code&gt;DBCC CLEANTABLE&lt;/code&gt; and it doesn&amp;rsquo;t fix this issue, but feel free to reproduce that if you want.)&lt;/p&gt;
&lt;p&gt;Even if you don&amp;rsquo;t want to reclaim the space, eventually your index may become fragmented enough that it qualifies for a rebuild in a maintenance job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Create and start an XEvents trace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We are creating this trace for two reasons:&lt;/p&gt;
&lt;p&gt;A. The trace is going to slow our instance down a lot because tracing locks is slloooowwww. So don&amp;rsquo;t do this on an instance where you care about performance. It&amp;rsquo;s actually handy for this to be slow because it gives you time to start up a read query that will be blocked and inspect the situation with sp_WhoIsActive without having to rush too much.&lt;/p&gt;
&lt;p&gt;B. The trace information is somewhat useful. We could filter it more, but see A.&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;SELECT @@SPID&lt;/code&gt; to find the session ID you&amp;rsquo;re going to use to rebuild the index. Then specify that session id in the trace definition.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;SPID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Locks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock_acquired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tsql_stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock_released&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tsql_stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ring_buffer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;NO_EVENT_LOSS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAX_EVENT_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MEMORY_PARTITION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PER_CPU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRACK_CAUSALITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;STARTUP_STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Locks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;START&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;6. Rebuild that index &amp;ldquo;online&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpk_lob&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOBTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REBUILD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ONLINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;7. Try to query the table in another session&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In another session, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOBTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;8. Look in horror upon your lock waits with sp_WhoIsActive&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a third session, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_locks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what you should see: Your supposedly online index rebuild blocking your select query, which is waiting with a &lt;code&gt;LCK_M_IS&lt;/code&gt; lock wait:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/LOBTest_table_online_index_rebuild_blocking_IS_waits.png"&gt;
&lt;/figure&gt;
&lt;p&gt;If you open the XML column for the locks for the &lt;code&gt;ALTER INDEX&lt;/code&gt; statement, you should see that the &lt;code&gt;ALTER INDEX&lt;/code&gt; statement has been granted an &lt;code&gt;X&lt;/code&gt; (exclusive) object lock on dbo.LOBTest. There are also a bunch of exclusive page locks&amp;ndash; in this case 233,345 of them.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/LOBTest_x_lock_sp_whoisactive.png"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;9. What&amp;rsquo;s in that XEvents trace?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a whole lot of locks in there, and among them you will see some X locks. Here&amp;rsquo;s the one on the object:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/LOBTest_x_lock_xEvents_trace.png"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;10. Stop and drop that trace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Goodbye, trace.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Locks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Locks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="so-what-to-do-when-onlinesad"&gt;So, What to do When Online=sad?&lt;/h2&gt;
&lt;p&gt;You might wonder, what do you do if you have a very large table and you can&amp;rsquo;t take an outage window to rebuild the clustered index offline?&lt;/p&gt;
&lt;p&gt;Yeah, I wonder that, too.&lt;/p&gt;
&lt;p&gt;You can run &lt;code&gt;DBCC CLEANTABLE&lt;/code&gt; to try to release some space.&lt;/p&gt;
&lt;p&gt;And you can exclude the clustered index from your index maintenance jobs, or configure it to only have &lt;code&gt;REORGANIZE&lt;/code&gt; operations, not &lt;code&gt;REBUILDS&lt;/code&gt;. Ever. (I&amp;rsquo;ve only tested this briefly&amp;ndash; the &lt;code&gt;REORGANIZE&lt;/code&gt; operation does take out &lt;code&gt;X&lt;/code&gt; locks, but in smaller/briefer batches and regularly releases them. I wouldn&amp;rsquo;t swear to that, though, it was just a quick test.)&lt;/p&gt;
&lt;p&gt;Aside from that, I really don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;Can you run a query to detect if any of your tables have had LOB columns dropped and are in a state where they might be prone to this issue? If you can, I haven&amp;rsquo;t figured out how yet.&lt;/p&gt;
&lt;p&gt;Hopefully this will get fixed before another couple of years elapse &amp;ndash; but I fear that note that was added to the documentation means it likely won&amp;rsquo;t.&lt;/p&gt;</description></item><item><title>Is the Azure SQL Managed Instance Business Critical Service Tier Worth the Cost?</title><link>https://kendralittle.com/2024/01/29/is-azure-sql-managed-instance-business-critical-service-tier-worth-the-cost/</link><pubDate>Mon, 29 Jan 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/01/29/is-azure-sql-managed-instance-business-critical-service-tier-worth-the-cost/</guid><description>&lt;p&gt;The Business Critical service tier in Azure SQL Managed Instance is a lot more expensive than General Purpose. For the extra money, you get a different architecture.&lt;/p&gt;
&lt;p&gt;Is it worth the extra cost? Spoiler: your mileage will vary, but probably not. Let&amp;rsquo;s talk about why.&lt;/p&gt;
&lt;h2 id="business-critical-architecture"&gt;Business Critical Architecture&lt;/h2&gt;
&lt;p&gt;In the Business Critical service tier, all databases are on local SSD on each node (instead of user databases being on blob storage). Data is transferred between nodes via compressed transaction log stream in an Availability Group-ish format. I say &amp;lsquo;Availability Group-ish&amp;rsquo; because the tech has clearly been customized quite a bit: it feels like SQL Server and Azure SQL Database had a baby and named it Managed Instance.&lt;/p&gt;
&lt;p&gt;As a result of these differences, you can&amp;rsquo;t see information in the same DMVs as a standard Availability Group.&lt;/p&gt;
&lt;h2 id="read-scale-out-instances-feel-half-baked"&gt;Read Scale-out Instances Feel Half-baked&lt;/h2&gt;
&lt;p&gt;You get one &amp;lsquo;read scale-out&amp;quot; instance with Business Critical at no extra charge, but it&amp;rsquo;s&amp;hellip; well, it&amp;rsquo;s limited. It&amp;rsquo;s so limited that I&amp;rsquo;m not a huge fan.&lt;/p&gt;
&lt;p&gt;While it&amp;rsquo;s true that this &amp;ldquo;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla?view=azuresql#business-critical-service-tier"&gt;provides 100% additional compute capacity at no extra charge to off-load read-only operations, such as analytical workloads, from the primary replica&lt;/a&gt;&amp;rdquo; &amp;ndash; there&amp;rsquo;s some fine print.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t get a normal connection string for a read scale-out instance. Instead, you connect to the primary replica with a connection property, &lt;code&gt;ApplicationIntent=ReadOnly&lt;/code&gt;. The read scale-out instance doesn&amp;rsquo;t emit performance counters, either. These limitations mean you are unlikely to be able to connect 3rd party monitoring tools to a read scale-out instance unless the vendor has specifically designed for these limitations. You can query some DMVs.&lt;/p&gt;
&lt;p&gt;Maybe there&amp;rsquo;s some sort of Azure monitoring you can rig up (which probably has a cost), but I can&amp;rsquo;t find any way to see the health of read scale-out instances in the Azure Portal by default. In fact, I can&amp;rsquo;t see anything about read scale-out instances in the portal at all. They&amp;rsquo;re pretty invisible.&lt;/p&gt;
&lt;p&gt;As in any Availability Group (ish) scenario, &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/read-scale-out?view=azuresql#long-running-queries-on-read-only-replicas"&gt;long running queries on the read scale-out instance can block DDL changes from the primary replica&lt;/a&gt;. There is an automated process to terminate those to keep things from getting too out of sync. (This is the exact kind of scenario that makes me want robust monitoring so I understand the impact. But&amp;hellip;. yeah.)&lt;/p&gt;
&lt;h2 id="instances-for-failover"&gt;Instances for Failover&lt;/h2&gt;
&lt;p&gt;There are a couple/few failover partners kept on the side for high availability (&amp;quot;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla?view=azuresql#business-critical-service-tier"&gt;up to three secondary replicas (compute and storage) that contain copies of data&lt;/a&gt;&amp;quot;), with data synced to these constantly.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure if there&amp;rsquo;s a guaranteed minimum number of replicas (I haven&amp;rsquo;t seen it documented), but there is clearly some kind of quorum involved/required to keep the primary online.&lt;/p&gt;
&lt;h2 id="architecture-drawing"&gt;Architecture Drawing&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureSQLManagedInstance-BusinessCritical-HA-Architecture.gif"&gt;
&lt;/figure&gt;
&lt;h2 id="is-the-cost-of-the-business-critical-architecture-worth-it"&gt;Is the Cost of the Business Critical Architecture Worth It?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a pricing comparison that I collected a week ago when I &lt;a href="https://kendralittle.com/2024/01/22/azure-sql-managed-instance-general-purpose-architecture/"&gt;wrote about the General Purpose Architecture&lt;/a&gt;. Using the East-US region as an example and assuming the instance needs to be on all the time for one year (8,760 hours):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service Tier&lt;/th&gt;
&lt;th&gt;Series&lt;/th&gt;
&lt;th&gt;Hourly Rate&lt;/th&gt;
&lt;th&gt;Annual Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;General Purpose&lt;/strong&gt; (16 vCore)&lt;/td&gt;
&lt;td&gt;Standard Series&lt;/td&gt;
&lt;td&gt;$4.035/hour&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$35,346.60&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;General Purpose&lt;/strong&gt; (16 vCore)&lt;/td&gt;
&lt;td&gt;Premium Series Memory Optimized&lt;/td&gt;
&lt;td&gt;$5.541/hour&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$48,539.16&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Business Critical&lt;/strong&gt; (16 vCore)&lt;/td&gt;
&lt;td&gt;Standard Series&lt;/td&gt;
&lt;td&gt;$10.871/hour&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$95,229.96&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Business Critical&lt;/strong&gt; (16 vCore)&lt;/td&gt;
&lt;td&gt;Premium Series Memory Optimized&lt;/td&gt;
&lt;td&gt;$13.883/hour&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$121,615.08&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;For simplicity I listed Standard Series and Memory Optimized at 16vCores&amp;ndash; use the &lt;a href="https://azure.microsoft.com/en-us/pricing/details/azure-sql-managed-instance/single/"&gt;pricing calculator&lt;/a&gt; if you want to see other options. These pricing examples don&amp;rsquo;t include Failover Groups&amp;mdash; multiply by 2 to estimate that.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On the one hand, the storage in Business Critical is faster than remote blob storage queried over http. (That&amp;rsquo;s not a high bar.)&lt;/p&gt;
&lt;p&gt;But on the other hand, if you modify much data, this is a LOT of nodes to sync to. You can run into HADR waits based on syncing to AG nodes, especially if you have a Business Critical partner in a Failover Group, and this can slow your write workload.&lt;/p&gt;
&lt;p&gt;Business Critical might be a better fit for you than General Purpose, depending on your workload, your write patterns, your budget, and your requirements for uptime, but I think in most cases you&amp;rsquo;ll be better off with the General Purpose service tier using memory-optimized instances to compensate for slow storage speeds, and perhaps a Failover Group to meet HA/DR requirements if you need protection in more than one region. (Yep, you pay extra for a failover partner. But if it&amp;rsquo;s General Purpose as well, 2 GP instances are still significantly cheaper than 1 BC instance with the pricing above.)&lt;/p&gt;
&lt;p&gt;Or maybe your best fit is a different service like Amazon RDS for SQL Server, or a VM solution.&lt;/p&gt;</description></item><item><title>Azure SQL Managed Instance General Purpose Architecture and Performance/Cost Tradeoffs</title><link>https://kendralittle.com/2024/01/22/azure-sql-managed-instance-general-purpose-architecture/</link><pubDate>Mon, 22 Jan 2024 09:26:35 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/01/22/azure-sql-managed-instance-general-purpose-architecture/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: Microsoft has announced the general availability of the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-azure-sql-managed-instance-next-gen-gp/ba-p/4092647"&gt;Next-gen General Purpose service tier&lt;/a&gt; for Azure SQL Managed Instance, which includes improvements to I/O latency, IOPS, and transaction log throughput. This post describes the original General Purpose blob storage. You don't want that.
&lt;/div&gt;
&lt;p&gt;Whether or not you use Azure SQL Managed Instance, you will likely be asked for an opinion on it eventually if you&amp;rsquo;re a SQL Server person.&lt;/p&gt;
&lt;p&gt;While the architecture is &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla"&gt;documented&lt;/a&gt;, it can be a bit of a long read and some of the gotchas are spread out over different pages &amp;ndash; so I&amp;rsquo;m drawing up the architecture of each service tier along with notable implications for the design on performance and cost. Here&amp;rsquo;s the scoop on General Purpose.&lt;/p&gt;
&lt;h2 id="architecture-for-managed-instance-in-general-purpose"&gt;Architecture for Managed Instance in General Purpose&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the basic architecture for the General Purpose Service Tier. It&amp;rsquo;s basically a failover cluster style design with one active virtual compute node and shared storage.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureSQLManagedInstance-GeneralPurpose-HA-Architecture.gif"&gt;
&lt;/figure&gt;
&lt;h2 id="gotchas-storage"&gt;Gotchas: Storage&lt;/h2&gt;
&lt;p&gt;The big old gotcha is that the shared storage is Azure Blob Storage, which is not renowned for its speed. There is also a &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits#file-io-characteristics-in-general-purpose-tier"&gt;maximum number of IOPs based on data file size&lt;/a&gt; which maxes out at a throughput of 250 MiB/s&amp;ndash; your IO will be throttled if it exceeds this.&lt;/p&gt;
&lt;p&gt;Because of the pokey storage, the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/high-availability-sla#general-purpose-service-tier"&gt;docs for General Purpose notes regarding failovers that&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a heavy workload might experience some performance degradation during the transition since the new database engine process starts with cold cache.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No kiddin'.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s an &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits#service-tier-characteristics"&gt;instance limit on maximum log write throughput&lt;/a&gt;, too. For transaction log writes on General Purpose you will be cruising at or below 4.5 MiB/s per vCore, Max 120 MiB/s per instance, and 22 - 65 MiB/s per DB (depending on log file size).&lt;/p&gt;
&lt;h2 id="what-about-memory"&gt;What About Memory?&lt;/h2&gt;
&lt;p&gt;While you can provision memory to compensate/lower physical reads for data files, there&amp;rsquo;s no individual &amp;lsquo;memory&amp;quot; slider&amp;ndash; the amount of memory you have is proportional to your number of vCores:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5.1GB RAM per vCore under Standard Series hardware: 8 vCore = only 40.8GB RAM&lt;/li&gt;
&lt;li&gt;7GB RAM per vCore under Premium Series: 8 vCore = only 56GB RAM&lt;/li&gt;
&lt;li&gt;13.6GB RAM per vCore under Premium Memory Optimized: 8 vCore= only 108.8 GB RAM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As someone who had multiple clients with 2TB of RAM on failover clusters 8 years ago on on-prem hardware, these numbers still take some getting used to. Busy SQL Servers eat memory like tourists at a Vegas luxury buffet.&lt;/p&gt;
&lt;p&gt;In effect, you&amp;rsquo;ll often need to overspend on CPU if you want to use buffer pool to reduce physical IO for larger databases &amp;ndash; make sure to factor that into cost estimates. And you&amp;rsquo;ll probably also end up having larger data files and log files than you might need, as well, in order to get more IOPs. (Yep, you pay for storage over 32GB, based on how big those files are, too.)&lt;/p&gt;
&lt;h2 id="pricing-examples-general-purpose-and-business-critical"&gt;Pricing Examples: General Purpose and Business Critical&lt;/h2&gt;
&lt;p&gt;With all these tradeoffs, you might think, &amp;ldquo;Why not just use Business Critical for databases with high performance requirements?&amp;rdquo; Well, Business Critical has its own gotchas that I&amp;rsquo;ll dig into in a future post, but arguably the biggest differentiator of the Business Critical Tier is &lt;a href="https://azure.microsoft.com/en-us/pricing/details/azure-sql-managed-instance/single/"&gt;price&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using the East-US region as an example and assuming the instance needs to be on all the time for one year (8,760 hours):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;16 vCore &lt;strong&gt;General Purpose&lt;/strong&gt; x Standard Series = $4.035/hour pay-as-you-go = &lt;strong&gt;$35,346.60/year&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;16 vCore &lt;strong&gt;General Purpose&lt;/strong&gt; x Premium Series Memory Optimized = $5.541/hour pay-as-you-go = &lt;strong&gt;$48,539.16/year&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;16 vCore &lt;strong&gt;Business Critical&lt;/strong&gt; x Standard Series = $10.871 pay-as-you-go = &lt;strong&gt;$95,229.96 /year&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;16 vCore &lt;strong&gt;Business Critical&lt;/strong&gt; x Premium Series Memory Optimized = $13.883/hour pay-as-you-go = &lt;strong&gt;$121,615.08/year&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;For simplicity I only listed Standard Series and Memory Optimized at 16vCores&amp;ndash; use the &lt;a href="https://azure.microsoft.com/en-us/pricing/details/azure-sql-managed-instance/single/"&gt;pricing calculator&lt;/a&gt; if you want to see other options. These pricing examples don&amp;rsquo;t include Failover Groups&amp;mdash; multiply by 2 to estimate that.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yep, you can pay $121K USD per year for &amp;mdash; let&amp;rsquo;s see&amp;mdash; only 217.6 GB of RAM if you&amp;rsquo;re at 16 vCores in the Business Critical Service Tier with Premium Series Memory Optimized. (Blinks)&lt;/p&gt;
&lt;p&gt;You can lower pricing using reserved capacity, but make sure you read limitations on &lt;a href="https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations"&gt;Self-service exchanges and refunds for Azure Reservations&lt;/a&gt; before committing. There are limitations on the refund policy like, &amp;ldquo;Azure doesn&amp;rsquo;t process any refund that exceeds the 50,000 USD limit in a 12-month window for a billing profile or EA enrollment.&amp;rdquo; So be very, very sure before you commit to reservations.&lt;/p&gt;
&lt;h2 id="will-managed-instance-pricing-go-down-in-some-way"&gt;Will Managed Instance Pricing Go Down in Some Way?&lt;/h2&gt;
&lt;p&gt;I do think Managed Instance is a great idea: I don&amp;rsquo;t want to administer failover clusters or Availability Groups myself&amp;ndash; and it&amp;rsquo;s rare that I meet anyone who loves doing that. Managed Services are very attractive to alleviate that pain point. And I do think that automated administration and management of these services is worth paying for.&lt;/p&gt;
&lt;p&gt;However, this is a VERY expensive service. I hope the value per dollar goes up in the future, both in terms of &lt;a href="https://kendralittle.com/2023/12/08/what-features-are-missing-from-azure-sql-managed-instance/"&gt;keeping Managed Instance up to date with features&lt;/a&gt; and in giving you more memory and faster storage for your dollar. In my (completely anecdotal personal opinion), price is one of the bigger blockers for adoption, as &lt;a href="https://www.red-gate.com/simple-talk/databases/sql-server/database-administration-sql-server/moving-sql-server-to-the-cloud-modernizing-stack-overflow-for-teams/"&gt;Aaron Bertrand explains regarding Stack Overflow&amp;rsquo;s Azure Migration&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="read-more"&gt;Read More&lt;/h2&gt;
&lt;p&gt;Check out more posts in this series: &lt;a href="https://kendralittle.com/2024/01/29/is-azure-sql-managed-instance-business-critical-service-tier-worth-the-cost/"&gt;Is the Azure SQL Managed Instance Business Critical Service Tier Worth the Cost?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Automatic Plan Correction Could Be a Great Auto Tuning Feature for SQL Server: Here Is What It Needs</title><link>https://kendralittle.com/2024/01/17/automatic-plan-forcing-could-be-great-but-isnt-sql-server/</link><pubDate>Wed, 17 Jan 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/01/17/automatic-plan-forcing-could-be-great-but-isnt-sql-server/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: The &lt;code&gt;sys.sp_configure_automatic_tuning&lt;/code&gt; stored procedure is now &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-configure-automatic-tuning-transact-sql"&gt;documented and supported&lt;/a&gt; by Microsoft. Thanks to the SQL Server Product team for this improvement.
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;ve written a bit about SQL Server&amp;rsquo;s &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/automatic-tuning/automatic-tuning?view=sql-server-ver16#automatic-plan-correction"&gt;Automatic Plan Correction&lt;/a&gt; feature before&amp;ndash; I have an hour long &lt;a href="https://kendralittle.com/course/automatic-plan-correction-in-query-store/"&gt;free course with demos on Automatic Plan Correction&lt;/a&gt; here on the site.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;m updating that course with a note: after using Automatic Plan Correction &lt;a href="https://dictionary.cambridge.org/us/dictionary/english/in-anger"&gt;in anger&lt;/a&gt; for a good amount of time, I do not recommend enabling the feature. I&amp;rsquo;ve had it cause too many performance problems, and there are not a ton of options for an administrator when it&amp;rsquo;s causing those problems.&lt;/p&gt;
&lt;p&gt;Meanwhile, becoming reliant on the feature for the places where it &lt;em&gt;does&lt;/em&gt; help makes it difficult to disable the feature. You end up stuck with a very weird set of problems that are oddly similar to the problems the feature was designed to solve.&lt;/p&gt;
&lt;p&gt;Further investment in the feature &lt;em&gt;could&lt;/em&gt; solve these problems and make this a great tool for customers. Here&amp;rsquo;s a run down of what Automatic Plan Correction needs from a user who has suffered from it.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/automatic-plan-correction-needs-help.png" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="its-an-all-or-nothing-feature-because-the-syssp_configure_automatic_tuning-procedure-was-never-finished-documented-and-supported"&gt;It&amp;rsquo;s an All or Nothing Feature Because the sys.sp_configure_automatic_tuning Procedure was Never Finished, Documented, and Supported&lt;/h2&gt;
&lt;p&gt;Picture it: you&amp;rsquo;re a DBA or developer who gets an alert that a key part of your application is running too slowly. You dig in and find that there&amp;rsquo;s a slow query causing the problem.&lt;/p&gt;
&lt;p&gt;You think, &amp;ldquo;maybe it&amp;rsquo;s parameter sniffing?&amp;rdquo; You use a tool like &lt;a href="https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/blob/main/sp_BlitzWho.sql"&gt;sp_BlitzWho&lt;/a&gt; to identify that the query is running long, and it even gives you a handy command to bump the query plan out of the shared plan cache so that a new plan might be compiled. You run that command.&lt;/p&gt;
&lt;p&gt;Nothing changes. New sessions running the query get the exact same plan, no matter how many times you bump it out of the cache.&lt;/p&gt;
&lt;p&gt;You start digging around and you finally find the plan in Query Store. You see that the plan is forced. If you look into &lt;code&gt;sys.query_store_plan&lt;/code&gt;, you see that the &lt;code&gt;plan_forcing_type&lt;/code&gt; is &amp;lsquo;Auto&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;This means that the automatic plan forcing feature is enabled, and has forced a plan in Query Store in an attempt to help performance. It may be still testing out if the plan is better or not, or it may actually believe that it&amp;rsquo;s better &amp;ndash; you&amp;rsquo;d have to go query the &lt;code&gt;sys.dm_db_tuning_recommendations&lt;/code&gt; table to figure that out. (Better do that fast, or the info may get cleared out&amp;ndash; it doesn&amp;rsquo;t get persisted across restarts/failovers,etc, and it also might be overwritten after statistics change.)&lt;/p&gt;
&lt;h2 id="how-do-you-fix-it"&gt;How do you fix it?&lt;/h2&gt;
&lt;p&gt;Short term: you can manually un-force the plan in Query Store. This will allow a new plan to be generated. The problem may come back, however, because un-forcing a plan doesn&amp;rsquo;t exclude a query from future automatic tuning cycles. (When will those restart? I donno, I don&amp;rsquo;t think it&amp;rsquo;s documented. But it&amp;rsquo;s not rare.)&lt;/p&gt;
&lt;p&gt;Long term: you can add a recompile hint to the query. &lt;a href="https://kendralittle.com/course/automatic-plan-correction-in-query-store/demo-recompile-automatic-tuning-and-manual-plan-forcing-in-query-store-14-minutes/"&gt;This will prevent Automatic Plan Correction from picking it up&lt;/a&gt;, but the trade off is that you are going to burn more CPU for that query every time it optimizes. If the query runs very frequently, or if you find a problem where a large set of queries has a regression (like I describe below with temp tables), that becomes a pretty expensive option.&lt;/p&gt;
&lt;p&gt;I suspect that the original design of the feature meant for users to be able to address this in different ways. &lt;a href="https://erikdarling.com/"&gt;Erik Darling&lt;/a&gt; noticed that there is a procedure in SQL Server named &lt;a href="https://github.com/MicrosoftDocs/sql-docs/issues/9432"&gt;sys.sp_configure_automatic_tuning which is not documented, and filed an issue asking about it&lt;/a&gt;. This procedure looks like one could use it in this way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_configure_automatic_tuning&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;option&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FORCE_LAST_GOOD_PLAN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/*Option*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;QUERY&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/*Target*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;type_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/*query_id from Query Store*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;option_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OFF&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/*Disable*/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although Erik notes that he saw this worked, I&amp;rsquo;ve had more mixed results in testing. It sort of worked&amp;ndash; but a new query id for the query I excluded was generated in Query Store and then automatic plan forcing went after THAT.&lt;/p&gt;
&lt;p&gt;This leads me to believe that the feature to manually configure plan forcing per query wasn&amp;rsquo;t completely finished, and it was cut from scope in order to get the feature shipped. (I am not a Microsoft MVP. I have no special knowledge here. I&amp;rsquo;m only guessing based on my own experiences as a product manager at various software companies.)&lt;/p&gt;
&lt;p&gt;I have found that the feature is badly needed, however, and I think it&amp;rsquo;s worth the time/investment for Microsoft to get &lt;code&gt;sys.sp_configure_automatic_tuning&lt;/code&gt; completed and working.&lt;/p&gt;
&lt;h2 id="some-queries-are-not-suitable-for-repeated-experimentation"&gt;Some Queries are Not Suitable for Repeated Experimentation&lt;/h2&gt;
&lt;p&gt;So, which kinds of queries might you want to exclude from Automatic Plan Correction? I&amp;rsquo;ve found there are two big groups. One of them could be fixed by Microsoft without fixing &lt;code&gt;sys.sp_configure_automatic_tuning&lt;/code&gt;&amp;ndash; but this one, not so much.&lt;/p&gt;
&lt;p&gt;The first group is queries that can&amp;rsquo;t afford experimentation. If you run a high performance OLTP system, you are likely going to have some queries that need to always be very fast. The Automatic Plan Correction feature works by experimentation: after you get several hundred runs of a query, if it notices some are slower than others, it will try forcing some of the faster execution plans, then observing if they get slower. If it regresses, it&amp;rsquo;ll unforce the plan and try another one. (Exactly how many will it try if you have many many plans? I&amp;rsquo;m donno, I don&amp;rsquo;t think this is documented. It seems like a lot.)&lt;/p&gt;
&lt;p&gt;Even if Automatic Plan Correction finds a plan to force that is nice and fast, it won&amp;rsquo;t last forever. Statistics updates, failovers, or other situations will cause the experimentation cycle to restart.&lt;/p&gt;
&lt;p&gt;This results in uneven performance, and a LOT of confusion whenever code on these mission critical queries is updated, as it can take a while for the plan forcing to kick in. There are two things to help this situation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Give users the ability to exclude individual queries without recompile hints via a working &lt;code&gt;sys.sp_configure_automatic_tuning&lt;/code&gt; procedure.&lt;/li&gt;
&lt;li&gt;Give users data that is persisted longer so that they can identify plans that are repeatedly forced, which ones regress, and which ones don&amp;rsquo;t. These can be either manually forced, or the queries and indexes can be tuned to stabilize performance. Currently, not enough data is persisted over time to make this workable without a huge time investment on the user&amp;rsquo;s part to regularly persist, groom, and analyze the data. But this ability could make the pain of uneven performance worth it&amp;ndash; because it would give information needed to help resolve the issues longer term.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="automatic-plan-correction-invented-temporary-table-sniffing-problems--and-they-hurt"&gt;Automatic Plan Correction Invented &amp;ldquo;Temporary Table Sniffing&amp;rdquo; Problems &amp;ndash; and They Hurt&lt;/h2&gt;
&lt;p&gt;Another class of queries that you likely want to exclude from Automatic Plan Correction is queries that read from temporary tables.&lt;/p&gt;
&lt;p&gt;One of the most common performance tuning techniques used with SQL Server is to break down complex queries into separate, smaller steps, using a temporary table to persist data calculated by the initial query. This helps you not create single massive queries with 50+ joins in them by staging a set of data with the core of your result set, then joining to it to get details in further steps.&lt;/p&gt;
&lt;p&gt;Temporary tables are often recommended for this because they support column and index statistics. These statistics help the SQL Server query optimizer understand how much data it is working with, and recompile query plans if the size of the data in the temporary table one one run is significantly larger than the last time it ran.&lt;/p&gt;
&lt;p&gt;Automatic Plan Correction breaks this performance tuning technique, in my experience. It will freeze query plans that read from temporary tables and prevent them from recompiling. I&amp;rsquo;ve seen some truly ridiculously bad performance from this happening.&lt;/p&gt;
&lt;p&gt;This is ironic/sad when you start to think about it. Automatic Plan Correction as a feature is designed to help with parameter sniffing problems, where a plan gets cached that may not suit the variations of parameters that are passed in on later executions. But with temporary tables, it basically creates a different temporary table &amp;ldquo;sniffing&amp;rdquo; problem: when it freezes plans, it is &amp;ldquo;sniffing&amp;rdquo; the plan based on the statistics coming out of the temp table in that iteration of the plan. So it creates a different flavor of the problem it&amp;rsquo;s designed to solve.&lt;/p&gt;
&lt;p&gt;I have code that reproduces this issue with the Stack Overflow database that I&amp;rsquo;ll publish in a future post&amp;ndash; it&amp;rsquo;s not that hard to show, but this post is big enough.&lt;/p&gt;
&lt;h2 id="two-things-could-solve-this"&gt;Two things could solve this&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Automatic Plan Correction could automatically exclude queries that read from temporary tables when there is a large number of plans (maybe greater than 10 or 15). This high number of plans likely indicates that the temp table is causing natural recompiles that are actually beneficial for performance.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sys.sp_configure_automatic_tuning&lt;/code&gt; procedure could be finished and given options to handle this type of exclusion.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="is-it-helping-you-overall-or-is-it-hurting-your-performance-more-the-data-doesnt-stick-around-long-enough-to-find-out"&gt;Is It Helping You Overall? or is It Hurting Your Performance More? the Data Doesn&amp;rsquo;t Stick Around Long Enough to Find Out.&lt;/h2&gt;
&lt;p&gt;I think Automatic Plan Correction has a lot of the ingredients to make an impressive feature that does a very important thing: save customers money.&lt;/p&gt;
&lt;p&gt;If a feature can make it possible for customers to demonstrate that enabling it saves them money, people will start shouting about it. They&amp;rsquo;ll recommend it to others. It&amp;rsquo;ll take off.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s not happening now. Currently, Automatic Plan Correction is enabled by default in Azure SQL Database and Azure SQL Managed Instance. Some customers disable it. I almost never hear of customers who don&amp;rsquo;t use Azure SQL who enable it. Part of that is likely that they never hear about it, because nobody is shouting about it. Part of it is probably hesitancy to turn something on without a clear way to understand and show if it is helping or hurting.&lt;/p&gt;
&lt;h2 id="to-fix-this"&gt;To fix this&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Data from &lt;code&gt;sys.dm_db_tuning_recommendations&lt;/code&gt; needs to be able to be persisted. Right now, you can only see data for current recommendations. There is only one row per query_id. What experiments were performed last week? Before the last restart? How many experiments have been performed overall for a given query, and what were the outcomes? Make it possible &amp;ndash; ideally simple&amp;ndash; for users to figure that out, and you&amp;rsquo;ve given users the tools to understand if you are saving them money. That&amp;rsquo;s a huge tool. You&amp;rsquo;ll get champions, adoption, increased advancement in the feature. This will also lead to greater product stickiness for SQL Server. (Could I rig this up myself as a user with duct tape and stubbornness? Probably. Do I have the time and think it&amp;rsquo;s worth the business investment for this code to be managed by an individual over time? Nah, it should be part of the feature.)&lt;/li&gt;
&lt;li&gt;A variant of this functionality could also exist when the feature is not fully enabled, based on the recommendations it makes alone. Reports could estimate how much savings might be realized if the feature is enabled.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="fun-times-with-automatically-forced-plans-in-a-failure-state-which-dont-un-force-themselves"&gt;Fun Times with Automatically Forced Plans in a Failure State Which Don&amp;rsquo;t Un-force Themselves&lt;/h2&gt;
&lt;p&gt;In my experience, it is not uncommon for automatic tuning to force a query plan which ends up in a &amp;ldquo;failure&amp;rdquo; state. You can view this in the &lt;code&gt;force_failure_count&lt;/code&gt; and &lt;code&gt;last_force_failure_reason&lt;/code&gt; columns of &lt;code&gt;sys.query_store_plan&lt;/code&gt;. Generally I see the &lt;code&gt;last_force_failure_reason&lt;/code&gt; to be &lt;code&gt;GENERAL_FAILURE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In theory, this shouldn&amp;rsquo;t necessarily create a big problem. And in my experience, it doesn&amp;rsquo;t usually cause a big problem. However, once I have had it cause a VERY weird problem of very extended compilation time for a query. The problem went away when the query plan forced that was in the &lt;code&gt;GENERAL_FAILURE&lt;/code&gt; state was removed.&lt;/p&gt;
&lt;p&gt;In either case, however, what I&amp;rsquo;m seeing is that Automatic Tuning is forcing a query plan, and then that plan forcing ends up failing&amp;ndash; and Automatic Tuning doesn&amp;rsquo;t notice and clean that up. It should notice and clean that up.&lt;/p&gt;
&lt;h2 id="automatic-plan-correction-has-great-potential-and-is-worth-further-investment"&gt;Automatic Plan Correction has Great Potential and is Worth Further Investment&lt;/h2&gt;
&lt;p&gt;Although I don&amp;rsquo;t recommend using this feature now, I think the issues with this feature are simply due to lack of continued investment and maturing the feature by Microsoft. That&amp;rsquo;s very fixable.&lt;/p&gt;
&lt;p&gt;I do believe that in many cases this feature can solve a lot of gnarly parameter sniffing problems! I wish I could recommend it. It just needs a few more levers to be added and to make it easier for users to analyze and share when it is working well, and if it is actually saving them resources and time.&lt;/p&gt;</description></item><item><title>Power BI Performance Tuning with Eugene Meidinger</title><link>https://kendralittle.com/2024/01/16/power-bi-performance-tuning-eugene-meidinger/</link><pubDate>Tue, 16 Jan 2024 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2024/01/16/power-bi-performance-tuning-eugene-meidinger/</guid><description>&lt;p&gt;&lt;a href="https://www.sqlgene.com/"&gt;Eugene Meidinger&lt;/a&gt; stops by the Dear SQL DBA Podcast to chat about Power BI Performance Tuning.&lt;/p&gt;
&lt;p&gt;We talk about the various engines and languages used in Power BI and big-picture strategies for getting performance from the start. Eugene then talks about the community of tools and techniques that can be used to dig in and solve performance problems in Power BI.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/power-bi-performance-eugene-meidinger.png" width="230"&gt;
&lt;/figure&gt;
&lt;h3 id="pick-your-favorite-way-to-listen-to-the-episode"&gt;Pick Your Favorite Way to Listen to the Episode&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/power-bi-performance-tuning-with-eugene-meidinger/id1117507864?i=1000641742305"&gt;Subscribe on Apple Podcasts&lt;/a&gt; &amp;ndash; if you leave a five star review, I appreciate you! That helps more folks find the podcast.&lt;/li&gt;
&lt;li&gt;Plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="or-watch-on-youtube"&gt;Or Watch on Youtube&lt;/h3&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/-NnHLQYf1sc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/@Kendra_Little"&gt;Youtube.com/@Kendra_Little&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="want-to-learn-more-about-performance-tuning-power-bi"&gt;Want to Learn More About Performance Tuning Power Bi?&lt;/h2&gt;
&lt;p&gt;Eugene&amp;rsquo;s new Pluralsight course on Perf tuning Power BI launches on February 5th. The first 50 sales will be only $20. If you don&amp;rsquo;t get one of those lucky spots, use code &lt;code&gt;RACOONS&lt;/code&gt; to get 50% off.&lt;/p&gt;
&lt;p&gt;Find more of Eugene&amp;rsquo;s content at &lt;a href="https://www.sqlgene.com/"&gt;sqlgene.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="find-more-from-the-dear-sql-dba-podcast"&gt;Find More from the Dear SQL DBA Podcast&lt;/h2&gt;
&lt;p&gt;This is Episode 80 of the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;Dear SQL DBA Podcast&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Microsoft is Breaking Database Compatibility Levels for SQL Server</title><link>https://kendralittle.com/2023/12/18/how-microsoft-breaking-database-compatibility-level-sql-server/</link><pubDate>Mon, 18 Dec 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/12/18/how-microsoft-breaking-database-compatibility-level-sql-server/</guid><description>&lt;p&gt;According to Microsoft&amp;rsquo;s &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-compatibility-level?view=sql-server-ver16"&gt;documentation&lt;/a&gt;, &amp;lsquo;Database compatibility level &amp;hellip; allow[s] the SQL Server Database Engine to be upgraded while keeping the same functional status for connecting applications by maintaining the same pre-upgrade database compatibility level.&amp;quot;&lt;/p&gt;
&lt;p&gt;But these days, the &amp;ldquo;functional status&amp;rdquo; of a database at a given compatibility level differs depending on whether you&amp;rsquo;re using SQL Server, Azure SQL Managed Instance, or Azure SQL Database &amp;ndash; and in the hosted versions it may change anytime without notice. Surprise, your database behaves differently now!&lt;/p&gt;
&lt;p&gt;The whole concept is breaking down, and this is bad news for users of both managed services and the boxed product.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Database-compatibility-sql-server.png" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="an-example-database-compatibility-level-150-sql-server-2019"&gt;An Example: Database Compatibility Level 150 (SQL Server 2019)&lt;/h2&gt;
&lt;p&gt;In November 2019, database compatibility level 150 became the &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/general-availability-database-compatibility-level-150-in-azure/ba-p/1003458"&gt;default for new databases created in Azure SQL Database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Compat level 150 introduced &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/intelligent-query-processing"&gt;intelligent query processing features&lt;/a&gt;. However, which query processing features were enabled if you use that compat level changed over time.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/intelligent-query-processing-details?view=sql-server-2017#scalar-udf-inlining"&gt;scalar UDF inlining feature&lt;/a&gt; was not available in Azure SQL Database or Azure SQL Managed Instance until &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/scalar-udf-inlining-now-available-on-azure-sql/ba-p/2728372"&gt;September 2021, nearly two full years later&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At that point, if you were already at compat level 150, scalar UDF automatic inlining just &amp;hellip; started&amp;hellip; happening. Maybe you saw the blog post, maybe you didn&amp;rsquo;t. That &amp;ldquo;functional status&amp;rdquo; of the database moved a lot right beneath your feet.&lt;/p&gt;
&lt;p&gt;That feature is basically magic, but magic is dangerous. Some queries get faster, some queries get slower.&lt;/p&gt;
&lt;h2 id="this-has-become-obvious-with-database-compat-level-160-sql-server-2022"&gt;This has Become Obvious with Database Compat Level 160 (SQL Server 2022)&lt;/h2&gt;
&lt;p&gt;I wrote in &lt;a href="https://kendralittle.com/2023/12/08/what-features-are-missing-from-azure-sql-managed-instance/"&gt;a recent post&lt;/a&gt; that SQL Server 2022 Intelligent Query Processing features are hugely incomplete in Azure SQL Managed Instance. (I think this is true for Azure SQL Database as well, but to be honest it&amp;rsquo;s a lot to keep straight, so let&amp;rsquo;s use MI as the example.)&lt;/p&gt;
&lt;p&gt;None of the following intelligent query processing features are available in Managed Instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cardinality Estimation Feedback&lt;/li&gt;
&lt;li&gt;Memory Grant Feedback (percentile)&lt;/li&gt;
&lt;li&gt;Memory Grant, Cardinality Estimation, and DOP feedback persistence&lt;/li&gt;
&lt;li&gt;Optimized plan forcing&lt;/li&gt;
&lt;li&gt;Parameter Sensitivity Plan Optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But let&amp;rsquo;s say you want to enable database compatibility level 160 so that you can use something like the new &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/generate-series-transact-sql"&gt;generate_series function&lt;/a&gt; or using &lt;code&gt;enable_ordinal&lt;/code&gt; in &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql"&gt;string_split&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When will all those performance-changing features listed above magically become enabled?&lt;/p&gt;
&lt;p&gt;How will you know?&lt;/p&gt;
&lt;p&gt;If they cause a regression, how will you be able to tell what changed, and how long will it take you?&lt;/p&gt;
&lt;p&gt;Dear reader, I am not excited to find out for myself, either.&lt;/p&gt;
&lt;h2 id="this-leaves-boxed-product-sql-server-users-feeling-experimented-on"&gt;This Leaves &amp;ldquo;Boxed Product&amp;rdquo; SQL Server Users Feeling Experimented On&lt;/h2&gt;
&lt;p&gt;The biggest group of users for SQL Server are still those who buy licenses and run the &amp;ldquo;boxed product&amp;rdquo; version, whether they are doing so on-prem or in VMs in the cloud. (I don&amp;rsquo;t say this from any official data, but from chatting with users and doing things like polling a room of ~100 students at a performance tuning day long session at conferences. There is some adoption of managed services for SQL Server, but it appears to be pretty limited, still.)&lt;/p&gt;
&lt;p&gt;These users tell me they wonder: &lt;em&gt;why&lt;/em&gt; aren&amp;rsquo;t these features available in the Managed Services?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Will they cause instability in Query Store, which then causes it to not work?&lt;/li&gt;
&lt;li&gt;Do they not fully work as designed?&lt;/li&gt;
&lt;li&gt;Do they cause a lot of regressions if you enable them?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no way to know, because Microsoft hasn&amp;rsquo;t documented &lt;strong&gt;why&lt;/strong&gt; these features aren&amp;rsquo;t available in Azure SQL Database or Managed Instance. Among users, I hear a lot of suspicions that if these features were effective and reliable, surely they would be made available to the people who Microsoft is working very hard to sell lucrative Managed Services to.&lt;/p&gt;
&lt;h2 id="there-are-database-level-controls-some-might-say-that-makes-it-worse-for-managed-instance-users-not-better"&gt;&amp;ldquo;There are Database Level Controls,&amp;rdquo; Some might Say. That Makes It Worse for Managed Instance Users, Not Better.&lt;/h2&gt;
&lt;p&gt;There are &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-scoped-configuration-transact-sql"&gt;database scoped configuration options&lt;/a&gt; for many of these features. Maybe all of them, it&amp;rsquo;s kind of hard to read the list in the document with everything being in all caps and the names using abbreviations/ different wordings.&lt;/p&gt;
&lt;p&gt;It is theoretically possible for a Managed Instance user who doesn&amp;rsquo;t want features to suddenly appear with minimal warning to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Diligently go through the documentation and manually disable all the settings for features which are not yet available for the service they are using in &lt;em&gt;each and every database&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Write automation to do this in new databases/instances.&lt;/li&gt;
&lt;li&gt;Manually review blogs and documentations every&amp;hellip; I don&amp;rsquo;t know how often&amp;hellip; to see if the features are available and then plan to test them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There may be one user in the world who does that. Maybe two or three. It&amp;rsquo;s a bad idea, though.&lt;/p&gt;
&lt;p&gt;This style of configuration is way too complicated. You&amp;rsquo;d have to document the reasoning all yourself and keep it up to date. It&amp;rsquo;s fragile: how likely is the upkeep of this configuration management likely to last if the person leading it changes teams? And it&amp;rsquo;s not even recommended by Microsoft: all the documentation says to rely on database compatibility levels. Going in this direction will only lead to weirdly configured instances that are hard to troubleshoot in the long term.&lt;/p&gt;
&lt;p&gt;This approach is &lt;em&gt;not&lt;/em&gt; why people want to adopt a hosted service for databases. It&amp;rsquo;s pretty much the opposite. And these are the kinds of problems that database compatibility level is supposed to make easier for users.&lt;/p&gt;
&lt;h2 id="make-database-compatibility-levels-make-sense-again"&gt;Make Database Compatibility Levels Make Sense Again&lt;/h2&gt;
&lt;p&gt;Dear Microsoft Senior leadership, there are two ways to handle this. Don&amp;rsquo;t let a database compatibility level mean totally different things in products which are supposed to be related, and which you can even fail over to one another.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When you make a database compatibility level available in the SQL Server engine, ensure you make &lt;strong&gt;all the same features&lt;/strong&gt; for that compat level available wherever it works as a standard practice.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Or&amp;hellip;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;You can ditch the concept of database compatibility levels altogether and stop promising that Azure SQL Managed Instance is &lt;a href="https://kendralittle.com/2023/12/08/what-features-are-missing-from-azure-sql-managed-instance/"&gt;always up to date with the latest SQL features and functionality&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But you need to pick one.&lt;/p&gt;</description></item><item><title>Getting Around Error 40510 to Configure Resource Governor in Azure SQL Managed Instance</title><link>https://kendralittle.com/2023/12/15/error_40510_resource_governor_azure_sql_managed_instance/</link><pubDate>Fri, 15 Dec 2023 08:42:12 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/12/15/error_40510_resource_governor_azure_sql_managed_instance/</guid><description>&lt;p&gt;One feature I&amp;rsquo;ve not appreciated enough in the past in SQL Server is Resource Governor.&lt;/p&gt;
&lt;p&gt;Resource Governor allows you to &lt;a href="https://erikdarling.com/enabling-resource-governor-to-fix-memory-grants/"&gt;fix problems with Memory Grants in a simple way, as Erik Darling recommends&lt;/a&gt;. It also lets you classify sessions into groups and limit the &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql?view=sql-server-ver16#group_max_requests--value"&gt;maximum number of simultaneous requests&lt;/a&gt;, and /or limit the &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql?view=sql-server-ver16#max_dop--value"&gt;degree of parallelism&lt;/a&gt; if you need more CPU for other workloads. While this will slow down the queries you classify into that group, this can be super useful, especially if you&amp;rsquo;re already using something like Snapshot isolation to prevent blocking or you are using a read-only replica.&lt;/p&gt;
&lt;p&gt;In Azure SQL Managed Instance, you get to use Resource Governor, even in the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/features-comparison?view=azuresql#features-of-sql-database-and-sql-managed-instance"&gt;General Purpose tier&lt;/a&gt;. This is awesome.&lt;/p&gt;
&lt;p&gt;Just make sure you execute commands in the context of the master database, or you&amp;rsquo;ll get error 40510: &lt;code&gt;Statement 'ALTER RESOURCE GOVERNOR' is not supported in this version of SQL Server.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It is supported! Just &lt;code&gt;USE master;&lt;/code&gt; before running your commands.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/raccoon-directing-traffic.png"
alt="Directing traffic" width="300"&gt;&lt;figcaption&gt;
&lt;p&gt;Directing traffic&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="at-first-i-thought-this-was-a-missing-feature"&gt;At First, I Thought This was a Missing Feature&lt;/h2&gt;
&lt;p&gt;When I first tested this, I believed the error message. I thought perhaps the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/features-comparison?view=azuresql#features-of-sql-database-and-sql-managed-instance"&gt;documentation&lt;/a&gt; was misleading and that the feature was only available in Business Critical, or in some way limited.&lt;/p&gt;
&lt;p&gt;Then I realized that I was executing the commands in the context of a user database. You can do this in the on-prem version of SQL Server, but Azure SQL Managed instance is architected a bit differently. When you start looking at your logs and system objects, you&amp;rsquo;ll notice things like database names actually being uniqueidentifiers, and lots of other little things you don&amp;rsquo;t see in an on-prem SQL Server.&lt;/p&gt;
&lt;p&gt;There are also some handy unique features, like the &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-server-resource-stats-azure-sql-database"&gt;sys.server_resource_stats&lt;/a&gt; view, which persists some performance data for ~14 days, even over restarts.&lt;/p&gt;
&lt;p&gt;But basically, some things like this work a little differently in Azure SQL Managed Instance, and I believe it&amp;rsquo;s related to the cloud-based architecture of the product.&lt;/p&gt;
&lt;h2 id="i-changed-my-database-context-to-master-and-it-works-perfectly"&gt;I Changed My Database Context to Master, and It Works Perfectly&lt;/h2&gt;
&lt;p&gt;Just include a &lt;code&gt;use master;&lt;/code&gt; statement at the top of your scripts and you won&amp;rsquo;t have an issue.&lt;/p&gt;
&lt;h2 id="a-note-about-this-is-now-in-the-docs"&gt;A Note About This is Now in the Docs&lt;/h2&gt;
&lt;p&gt;I think one of the most common commands folks use for Resource Governor these days is &lt;code&gt;ALTER WORKLOAD GROUP&lt;/code&gt;, like Erik &lt;a href="https://erikdarling.com/enabling-resource-governor-to-fix-memory-grants/"&gt;suggests in his post&lt;/a&gt;. I submitted &lt;a href="https://github.com/MicrosoftDocs/sql-docs/pull/9547"&gt;a PR to the docs&lt;/a&gt; to add a note to that page, which has been merged.&lt;/p&gt;
&lt;p&gt;Hopefully this makes the ride smoother for others who need to do a little traffic direction for their workloads on Managed Instance.&lt;/p&gt;</description></item><item><title>How Many Features Are Missing from Azure SQL Managed Instance?</title><link>https://kendralittle.com/2023/12/08/what-features-are-missing-from-azure-sql-managed-instance/</link><pubDate>Fri, 08 Dec 2023 21:45:01 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/12/08/what-features-are-missing-from-azure-sql-managed-instance/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE (November 2025)&lt;/strong&gt;: Since this post was written,
&lt;strong&gt;most Intelligent Query Processing features are now available.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;
According to &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/intelligent-query-processing#iqp-features-for-azure-sql-managed-instance"&gt;Microsoft documentation&lt;/a&gt;, most Intelligent Query Processing features are now available in Azure SQL Managed Instance, including Cardinality Estimation Feedback, Memory Grant Feedback (percentile), and Parameter Sensitivity Plan Optimization. Some features require specific database compatibility levels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage increases:&lt;/strong&gt; Business Critical service tier now supports up to 16 TB of storage (increased from 4 TB), and the new &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits"&gt;Next-gen General Purpose service tier&lt;/a&gt; supports up to 32 TB. See &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits"&gt;resource limits documentation&lt;/a&gt; for details.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next-gen General Purpose (GPV2) improvements:&lt;/strong&gt; The new Next-gen General Purpose service tier eliminates the need to configure abnormally large file sizes to get IOPS and throughput. This limitation only applied to the original General Purpose (GPV1) tier, where file sizes determined IOPS and throughput allocation.&lt;/li&gt;
&lt;/ul&gt;
&lt;strong&gt;Still missing:&lt;/strong&gt; The following features remain unavailable in Azure SQL Managed Instance as of November 2025, along with most of the features in the post not listed above.
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/optimized-plan-forcing-query-store"&gt;Optimized plan forcing with Query Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/databases/tempdb-database#memory-optimized-tempdb-metadata"&gt;Memory optimized tempdb metadata&lt;/a&gt; (SQL Server 2019 feature)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/how-query-store-collects-data"&gt;Writable Query Store on Readable Secondaries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Spoiler: a large amount of features from SQL Server 2022 are missing from Azure SQL Managed Instance. Some major features are missing that were introduced in SQL Server &lt;strong&gt;2019&lt;/strong&gt;&amp;ndash; and here we are just a few weeks away from 2024.&lt;/p&gt;
&lt;p&gt;But Microsoft&amp;rsquo;s &lt;a href="https://azure.microsoft.com/en-us/products/azure-sql/managed-instance"&gt;top-line marketing claims about Azure SQL Managed Instance&lt;/a&gt; remain that &amp;lsquo;it&amp;rsquo;s always up to date with the latest SQL features and functionality.&amp;rsquo;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dig into some of the documented highlights on missing features, so you can decide for yourself what to think of that statement.&lt;/p&gt;
&lt;h2 id="the-marketing-claim-vs-reality"&gt;The Marketing Claim vs Reality&lt;/h2&gt;
&lt;p&gt;On its main product page, the &lt;a href="https://azure.microsoft.com/en-us/products/azure-sql/managed-instance"&gt;pitch for Azure SQL Managed Instance&lt;/a&gt; is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Always operate on the latest version of SQL.
Stop worrying about updates, upgrades, or end of support. SQL Managed Instance is built on the SQL Server engine, so it&amp;rsquo;s always up to date with the latest SQL features and functionality.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Managed Instance users DO need to worry about upgrades, because they are constantly confused about what Managed Instance can and can&amp;rsquo;t do at a given time compared to &amp;ldquo;normal&amp;rdquo; / boxed-product SQL Server. Some information is in documentation, but it&amp;rsquo;s scattered about in many places. Other limitations, well, users discover them on their own.&lt;/p&gt;
&lt;h2 id="sql-server-2022-features-missing-or-incomplete"&gt;SQL Server 2022 Features: Missing or Incomplete&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.brentozar.com/archive/2023/05/its-been-6-months-sql-server-2022-still-isnt-ready-yet/"&gt;Brent Ozar has written about how Azure SQL Managed Instance Link&lt;/a&gt;, a big hero of the SQL Server 2022 release, was in a gated private preview that could only be accessed after filling out a form and waiting in a queue of indeterminate length. The feature is now in Public Preview (ungated) as of &lt;a href="https://techcommunity.microsoft.com/t5/azure-sql-blog/online-disaster-recovery-between-sql-server-2022-and-sql-managed/ba-p/3982330"&gt;November 15, 2023&lt;/a&gt;, but as Brent writes: &amp;ldquo;It&amp;rsquo;s amazing to me that even a year after its release, SQL Server 2022&amp;rsquo;s flagship feature still isn&amp;rsquo;t ready yet.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Writable Query Store on Readable Secondaries remains in preview for the boxed product, but this feature is not available at all in Azure SQL Managed Instance. I see no way to even preview it.&lt;/p&gt;
&lt;p&gt;Most Intelligent Query Processing features are now available in Azure SQL Managed Instance (see the update note at the top of this post). However, &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-store-plan-transact-sql"&gt;Optimized plan forcing with Query Store&lt;/a&gt; remains unavailable as of November 2025.&lt;/p&gt;
&lt;h2 id="sql-server-2019-features-still-missing"&gt;SQL Server 2019 Features Still Missing&lt;/h2&gt;
&lt;p&gt;I wrote a feedback article on the lack of the SQL Server 2019 feature &lt;a href="https://feedback.azure.com/d365community/idea/590d88c1-ec95-ee11-a81c-000d3ae6a6aa"&gt;memory optimized tempdb metadata&lt;/a&gt; in Managed Instance. Essentially, tempdb metadata contention occurs on system tables when you use tempdb at higher volumes. Unlike other types of tempdb contention, this can&amp;rsquo;t be alleviated by adding multiple data files, as these system tables only ever reside in one data file in tempdb. But if you hit this problem in Managed Instance, the feature that fixes it isn&amp;rsquo;t available to you.&lt;/p&gt;
&lt;p&gt;Only recently, Microsoft made it possible to add data files to tempdb in Managed Instance. However, you might notice that there are &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/tempdb-configure"&gt;commands to add files and remove files&lt;/a&gt;, but NOT to set the file size or to grow files. How do you make tempdb files the same size in Azure SQL Managed Instance to follow Microsoft&amp;rsquo;s own &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/tempdb-configure"&gt;performance guidelines for tempdb&lt;/a&gt;? I don&amp;rsquo;t see how one can.&lt;/p&gt;
&lt;h2 id="database-and-instance-limitations"&gt;Database and Instance Limitations&lt;/h2&gt;
&lt;p&gt;You can&amp;rsquo;t have more than 100 databases per instance. Not all databases are of equal size, activity, or usage, so this cap seems weirdly arbitrary to me. But there it is.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t get minimal logging (no Simple or Bulk Recovery Models). Minimal logging is really nice for staging data and temporary workspaces. For many of these use cases, data loss of staged data is not a huge problem&amp;ndash; you&amp;rsquo;d start the process over again anyway. However, you can&amp;rsquo;t do this anywhere but tempdb on SQL Server Managed Instance. Remember those limitations for tempdb I mentioned above? Not fantastic.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t lower the max server memory. Would you like to test how things perform if you scale down to have less memory? Well, the normal way to do this won&amp;rsquo;t work, time to get on your bad idea jeans.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t take database snapshots or use DBCC CLONEDATABASE. DBCC CLONEDATABASE is really handy and useful. Sigh.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t change the time zone after the instance is created. Hope you don&amp;rsquo;t want to.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t use single user mode. This one I kind of understand, because they don&amp;rsquo;t want their processes to be locked out&amp;ndash; but it still means that you need to create workarounds if you use this for maintenance.&lt;/p&gt;
&lt;h2 id="maintenance-and-troubleshooting-gaps"&gt;Maintenance and Troubleshooting Gaps&lt;/h2&gt;
&lt;p&gt;You can&amp;rsquo;t run DBCC CHECKDB with options REPAIR_ALLOW_DATA_LOSS, REPAIR_FAST, and REPAIR_REBUILD. Hopefully you don&amp;rsquo;t need to, but it&amp;rsquo;s good to understand this ahead of time.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t change the number of error logs, or even keep your error logs. This one makes me sad:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Error logs that are available in SQL Managed Instance aren&amp;rsquo;t persisted, and their size isn&amp;rsquo;t included in the maximum storage limit. Error logs might be automatically erased if failover occurs. There might be gaps in the error log history because SQL Managed Instance was moved several times on several virtual machines.&amp;rdquo; &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/doc-changes-updates-known-issues#tempdb-structure-and-content-is-re-created"&gt;Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can&amp;rsquo;t use instant file initialization, so you may wait for file growths. Azure storage ain&amp;rsquo;t famous for being fast.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;A SQL Database managed instance does not use instant file initialization, so you might see additional PREEMPTIVE_OS_WRITEFILEGATHER wait statistics since the date files are filled with zero bytes during file growth.&amp;rdquo; &lt;a href="https://azure.microsoft.com/en-us/blog/key-causes-of-performance-differences-between-sql-managed-instance-and-sql-server/"&gt;docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="features-that-just-arent-there"&gt;Features That Just Aren&amp;rsquo;t There&lt;/h2&gt;
&lt;p&gt;You can&amp;rsquo;t use Filestream, Filetable, Fulltext Semantic Search, Merge Replication, Peer to Peer Replication, or Replication with Updatable Subscriptions. I thought a lot of these features were overhyped/not great anyway, but a lot of people disagree with me about that.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t use some columnstore index features&amp;ndash; maybe? Hard for me to tell if &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-what-s-new"&gt;this doc&lt;/a&gt; applies to managed instance or if it&amp;rsquo;s up to date.&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t use event notifications. I actually liked that feature. Maybe I was the only one.&lt;/p&gt;
&lt;h2 id="log-shipping-and-backup-limitations"&gt;Log Shipping and Backup Limitations&lt;/h2&gt;
&lt;p&gt;You can&amp;rsquo;t use log shipping for anything other than migrating to MI. The only log shipping service available in Managed Instance is the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/log-replay-service-migrate?tabs=sas-token"&gt;Log Replay Service&lt;/a&gt;. As far as I can tell from reading, that only works with Managed Instance as the destination. If this is incorrect, please correct me in the comments.&lt;/p&gt;
&lt;p&gt;Isn&amp;rsquo;t it always a little creepy when it&amp;rsquo;s easier to get into something than it is to get out?&lt;/p&gt;
&lt;p&gt;Also &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/log-replay-service-overview?source=recommendations"&gt;note&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;LRS is the only method to restore differential backups on managed instances. It isn&amp;rsquo;t possible to manually restore differential backups on managed instances or to manually set the NORECOVERY mode by using T-SQL.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="storage-and-performance-quirks"&gt;Storage and Performance Quirks&lt;/h2&gt;
&lt;p&gt;You can&amp;rsquo;t have reasonably sized data and log files in General Purpose. &amp;ldquo;In the General Purpose service tier, every database file gets dedicated IOPS and throughput that depend on the file size.&amp;rdquo; &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/resource-limits#file-io-characteristics-in-general-purpose-tier"&gt;Docs&lt;/a&gt; Having to create artificially large files gets real weird, real fast. And of course you get to pay for the storage.&lt;/p&gt;
&lt;h2 id="i-know-theres-more"&gt;I Know There&amp;rsquo;s More&lt;/h2&gt;
&lt;p&gt;I know there&amp;rsquo;s more, and I&amp;rsquo;ve probably missed something obvious. But you get the picture.&lt;/p&gt;
&lt;h2 id="how-do-we-fix-this"&gt;How do We Fix This?&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t think it&amp;rsquo;s our responsibility as customers to fix this. I&amp;rsquo;ve been told by Microsoft folks that I should create &amp;ldquo;suggestions&amp;rdquo; for missing features in their forums, but&amp;hellip; really?&lt;/p&gt;
&lt;p&gt;Why should users need to file suggestions that a vendor &lt;strong&gt;follow the primary pitch for their own product&lt;/strong&gt;? My time and your time is valuable, friends. We shouldn&amp;rsquo;t have to write suggestions and vote so that someone can pick and choose how they live up to their own commitments: they &lt;strong&gt;already&lt;/strong&gt; committed to doing that.&lt;/p&gt;
&lt;p&gt;If you are considering or using Managed Instance, perhaps let Microsoft Sales know that you are concerned about the number of missing features in Azure SQL Managed Instance, and that it&amp;rsquo;s important to you to have the latest features from SQL Server available. Not the imaginary ones, the actual ones.&lt;/p&gt;</description></item><item><title>Lost Updates Under Read Committed Snapshot Isolation (RCSI)</title><link>https://kendralittle.com/2023/10/04/lost-updates-rcsi/</link><pubDate>Wed, 04 Oct 2023 08:28:49 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/10/04/lost-updates-rcsi/</guid><description>&lt;p&gt;I shared an image on social media this week that describes how I feel about isolation levels in SQL Server (and its various flavors): the more concurrent sessions you have in a database reading and writing data at the same time, the more attractive it is to use version-based optimistic locking for scalability reasons.&lt;/p&gt;
&lt;p&gt;There are two isolation levels in SQL Server that use optimistic locking for disk-based tables:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read Committed Snapshot Isolation (RCSI), which changes the implementation of the default Read Committed Isolation level and enables statement-based consistency.&lt;/li&gt;
&lt;li&gt;Snapshot Isolation, which provides high consistency for transactions (which often contain multiple statements). Snapshot Isolation also provides support for identifying update conflicts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Many folks get pretty nervous about RCSI when they learn that certain timing effects can happen with data modifications that don&amp;rsquo;t happen under Read Committed. The irony is that RCSI does &lt;em&gt;solve&lt;/em&gt; many OTHER timing risks in Read Committed, and overall is more consistent, so sticking with the pessimistic implementation of Read Committed is not a great solution, either.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/compare-sql-server-isolation-levels.png"&gt;
&lt;/figure&gt;
&lt;h2 id="race-conditions--timing-issues-under-rcsi"&gt;Race conditions / timing issues under RCSI&lt;/h2&gt;
&lt;p&gt;Like many folks, I chat with various AI assistants these days. Although their claims require fact-checking, they help me understand concepts I&amp;rsquo;ve had a hard time getting my head around, as well as improve my wording on concepts I already DO understand. And unlike some forums, AI doesn&amp;rsquo;t chastise me that my question&amp;rsquo;s already been asked by user GoblinFeet1000 and will reword things without judgement until I catch on. (Aside: one example is the Halloween problem.)&lt;/p&gt;
&lt;p&gt;So I gave GitHub CoPilot the prompt: &amp;ldquo;what specific kinds of lost updates can happen under read committed snapshot isolation level in sql server&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my improved summary of RCSI&amp;rsquo;s timing issues after its help:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Under RCSI, readers generally don&amp;rsquo;t block writers, and writers don&amp;rsquo;t block readers. This means it allows transactions to read data that has been modified by other transactions but not yet committed. If one transaction reads data that another transaction has modified but not yet committed, and then attempts to update that data, the second transaction&amp;rsquo;s changes may be lost when the first transaction commits. This doesn&amp;rsquo;t happen with every type of modification, but some query plans for modification allow this risk.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But even re-worded, that explanation can make people pretty nervous to enable RCSI. (Note: if you&amp;rsquo;d like a technical post on timing issues under RCSI, &lt;a href="https://sqlperformance.com/2014/05/t-sql-queries/read-committed-snapshot-isolation"&gt;Paul White has written a great one&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="rcsi-fixes-many-timing-issues-you-already-have-with-read-committed"&gt;RCSI fixes many timing issues you already have with Read Committed&lt;/h2&gt;
&lt;p&gt;Read Committed has plenty of its own timing issues, it&amp;rsquo;s just that most people figure they already have it and nobody is complaining, so it&amp;rsquo;s &amp;ldquo;comfortable&amp;rdquo; as the status quo.&lt;/p&gt;
&lt;p&gt;Under Read Committed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Queries can miss rows entirely if they are modified in a way that relocates them in an index while a scan is ongoing.&lt;/li&gt;
&lt;li&gt;Similarly, rows can be counted twice for the same reason.&lt;/li&gt;
&lt;li&gt;Non-repeatable reads are allowed in transactions, so if you query something twice, it may have changed without explanation. (This can even happen within the a single query plan if it needs to read data twice.)&lt;/li&gt;
&lt;li&gt;Phantom reads are allowed in transactions, so if you read something twice something may have been added without explanation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If good accuracy is needed for data in a highly concurrent situation, it&amp;rsquo;s not a great solution to stick with this!&lt;/p&gt;
&lt;p&gt;According to ChatGPT, that would be like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Refusing a medicine that cures six ailments because it might cause one side effect.&lt;/li&gt;
&lt;li&gt;Not using a safety net while tightrope walking because it might snap, even though it would save you from multiple deadly falls.&lt;/li&gt;
&lt;li&gt;Not to carry an umbrella because it might get windy, even when the forecast predicts heavy rain.&lt;/li&gt;
&lt;li&gt;A traveler in the desert avoiding an oasis because of a rumored snake, while ignoring the clear water that could save them from thirst.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-way-forward-protect-your-modifications"&gt;The way forward: protect your modifications&lt;/h2&gt;
&lt;p&gt;One essential thing is to recognize that protecting yourself against data inaccuracies with timing conditions is a requirement for using databases, no matter what isolation level you use.&lt;/p&gt;
&lt;p&gt;For your data modifications, you can protect them from the risk of edge conditions by examining them and identifying what isolation level they actually need. Your queries that do modifications perhaps should run under repeatable read, serializable, or snapshot isolation level to avoid race conditions, depending on your patterns and your requirements. This can co-exist with RCSI&amp;ndash; it doesn&amp;rsquo;t replace the need to sometimes use a different isolation level, it only changes how Read Committed is implemented.&lt;/p&gt;
&lt;p&gt;If both scalability and data correctness matter, this is worth your time (even if you stick with pessimistic Read Committed as your default). Start by identifying the most frequent and most critical transactions that do modifications for your application, and identify what level of protection they need.&lt;/p&gt;
&lt;p&gt;And if you decide that the risk of a few edge conditions is tolerable after looking at this, you might &lt;a href="https://michaeljswart.com/2022/11/use-rcsi-to-tackle-most-locking-and-blocking-issues-in-sql-server/"&gt;just enable RCSI&lt;/a&gt; like Michael J Swart&amp;rsquo;s team eventually decided to do.&lt;/p&gt;</description></item><item><title>Automated Deployments and the Art of the Database with Database Michael J Swart</title><link>https://kendralittle.com/2023/09/26/automated-deployments-art-of-database-michael-j-swart/</link><pubDate>Tue, 26 Sep 2023 11:39:38 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/09/26/automated-deployments-art-of-database-michael-j-swart/</guid><description>&lt;p&gt;In this episode, Michael J Swart joins the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;Dear SQL DBA Podcast&lt;/a&gt; to talk about databases, automation, and how he&amp;rsquo;s come to illustrate some of the coolest blog posts ever to be written about data.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/0JzcexfMysM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="about-michael-j-swart"&gt;About Michael J Swart&lt;/h2&gt;
&lt;p&gt;Check out Michael&amp;rsquo;s art and blog posts at &lt;a href="https://michaeljswart.com/"&gt;michaeljswart.com,&lt;/a&gt; and explore his posts by illustration at &lt;a href="https://michaeljswart.com/browse-articles-by-illustration/"&gt;https://michaeljswart.com/browse-articles-by-illustration/&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="find-more-from-the-dear-sql-dba-podcast"&gt;Find more from the Dear SQL DBA Podcast&lt;/h2&gt;
&lt;p&gt;This is Episode 79 of the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;Dear SQL DBA Podcast&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pick your favorite way to get more free content:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/c/LittleKendra"&gt;Youtube.com/@Kendra_Little&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;Subscribe on Apple Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>PAGELATCH, PAGEIOLATCH, and LATCH Waits in SQL Server</title><link>https://kendralittle.com/2023/09/12/sql-server-wait-stats-pagelatch-pageiolatch-latch/</link><pubDate>Tue, 12 Sep 2023 09:59:09 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/09/12/sql-server-wait-stats-pagelatch-pageiolatch-latch/</guid><description>&lt;p&gt;I&amp;rsquo;ve long found it tricky to remember and explain the differences between three similar-sounding waits in SQL Server that all have &amp;ldquo;LATCH&amp;rdquo; in the name: PAGELATCH, LATCH, and PAGEIOLATCH waits.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an illustration that explains these waits, along with wait subtypes.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/latch-related-wait-stats.png"&gt;
&lt;/figure&gt;
&lt;h2 id="quick-comparison"&gt;Quick Comparison&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a table that compares the three latch wait types:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Wait Type&lt;/th&gt;
&lt;th&gt;Contains &amp;ldquo;IO&amp;rdquo;?&lt;/th&gt;
&lt;th&gt;Contains &amp;ldquo;PAGE&amp;rdquo;?&lt;/th&gt;
&lt;th&gt;Page Location&lt;/th&gt;
&lt;th&gt;What It Means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PAGEIOLATCH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;On disk (storage)&lt;/td&gt;
&lt;td&gt;Waiting to read pages from disk into memory buffers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PAGELATCH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;In memory&lt;/td&gt;
&lt;td&gt;Waiting to access pages that are already in memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LATCH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;N/A (not a page)&lt;/td&gt;
&lt;td&gt;Waiting to access a structure or resource in memory that is not a data page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="pageiolatch-waits"&gt;PAGEIOLATCH Waits&lt;/h2&gt;
&lt;p&gt;PAGEIOLATCH at least has a giveaway in its name: the &amp;ldquo;IO&amp;rdquo; characters indicate I/O, aka &amp;ldquo;Input/Output&amp;rdquo; - a reference to transferring data, in this case from storage to memory.&lt;/p&gt;
&lt;p&gt;My definition: &amp;ldquo;I need to get PAGES from DISK (storage) into BUFFERS in memory. To investigate or reduce this wait, find queries with highest reads and look for indexing and tuning improvements.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql#WaitTypes"&gt;Microsoft docs definition&lt;/a&gt;: &amp;ldquo;Occurs when a task is waiting on a latch for a buffer that is in an I/O request.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="pagelatch-waits"&gt;PAGELATCH Waits&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s no &amp;ldquo;IO&amp;rdquo; in this one. That&amp;rsquo;s because the page is already in memory.&lt;/p&gt;
&lt;p&gt;My definition: I need to get access to a page that is already in memory. Sometimes this is &amp;ldquo;last page&amp;rdquo; insert contention, Page Free Space (PFS) contention, or tempdb contention.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql#WaitTypes"&gt;Microsoft docs definition&lt;/a&gt;: &amp;ldquo;Occurs when a task is waiting on a latch for a buffer that isn&amp;rsquo;t in an I/O request.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="latch-waits"&gt;LATCH Waits&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s no &amp;ldquo;PAGE&amp;rdquo; or &amp;ldquo;IO&amp;rdquo; in this one. This one is the hardest to explain, too.&lt;/p&gt;
&lt;p&gt;My definition: I need to access a structure or resource in memory that is NOT a data page. Can be anything from transaction log management to supporting parallel scans.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql#WaitTypes"&gt;Microsoft docs definition&lt;/a&gt;: &amp;ldquo;Occurs when waiting for an [latch subtype] latch. This doesn&amp;rsquo;t include buffer latches or transaction mark latches.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="wait-subtypes-ex-up-sh"&gt;Wait Subtypes: EX, UP, SH&lt;/h2&gt;
&lt;p&gt;First, there are more subtypes than these three (KP, DT) - but these are the most common subtypes I see. Here is how I remember these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;_UP = Update: I need to make some mods but others can read&lt;/li&gt;
&lt;li&gt;_EX = Exclusive: I need this to myself, everyone else wait&lt;/li&gt;
&lt;li&gt;_SH = Shared: I need to read this&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="learn-more-about-waits"&gt;Learn More About Waits&lt;/h2&gt;
&lt;p&gt;There are tons of great free resources to learn about wait types on the web. Some of my favorites are from Microsoft Learn and Paul Randal of SQL Skills:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql#WaitTypes"&gt;List of waits: sys.dm_os_wait_stats&lt;/a&gt; (Microsoft Learn)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide"&gt;Transaction Locking and Row Versioning Guide&lt;/a&gt; (Microsoft Learn)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sqlskills.com/help/waits/"&gt;Wait Stats Library&lt;/a&gt; (SQLskills)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/diagnose-resolve-latch-contention"&gt;Latch Contention Whitepaper&lt;/a&gt; (Microsoft Learn)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sqlskills.com/help/latches/"&gt;Latch Classes Library&lt;/a&gt; (SQLskills)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sqlskills.com/blogs/paul/most-common-latch-classes-and-what-they-mean/"&gt;Most common latch classes&lt;/a&gt; (SQLskills)&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Jer and Kendar Explore Optimized Locking</title><link>https://kendralittle.com/2023/09/04/jer-and-kendar-explore-optimized-locking/</link><pubDate>Mon, 04 Sep 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/09/04/jer-and-kendar-explore-optimized-locking/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE (November 2025)&lt;/strong&gt;: Microsoft has introduced &lt;a href="https://techcommunity.microsoft.com/blog/sqlserver/introducing-optimized-locking-v2/4468745"&gt;optimized locking v2&lt;/a&gt; with significant improvements. The new version includes &lt;strong&gt;Skip Index Locks (SIL)&lt;/strong&gt; and &lt;strong&gt;Query Plan LAQ Feedback Persistence&lt;/strong&gt;, which further reduce lock overhead. The improvements are most pronounced for nonclustered indexes. Optimized locking v2 is available in SQL Server 2025 and Azure SQL.
&lt;/div&gt;
&lt;p&gt;SQL Server has a new feature that&amp;rsquo;s currently only available in Azure SQL Database: Optimized Locking.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.facility9.com/"&gt;Jeremiah Peschka&lt;/a&gt; joins Kendra (aka Kendar) to talk through &lt;a href="https://learn.microsoft.com/sql/relational-databases/performance/optimized-locking"&gt;the docs&lt;/a&gt; and nerd out on locks, blocks, and how to pronounce the acronym &amp;ldquo;LAQ&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Prefer to explore optimized locking with a diagram? I&amp;rsquo;ve also got a little sketchnote for ya.&lt;/p&gt;
&lt;h2 id="podcast-episode"&gt;Podcast episode&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/AL3CO6daCbc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="sketchnote-of-optimized-locking-concepts"&gt;Sketchnote of optimized locking concepts&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a sketchnote style comic I drew up of what I&amp;rsquo;ve learned about the feature so far.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/free-sql-comics/20230904-exploring-optimized-locking.png"
alt="Right click and open in new tab for larger image"&gt;&lt;figcaption&gt;
&lt;p&gt;Right click and open in new tab for larger image&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="learn-more-about-optimized-locking"&gt;Learn more about optimized locking&lt;/h2&gt;
&lt;p&gt;Learn more about this feature online:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/sql/relational-databases/performance/optimized-locking"&gt;Optimized locking article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide"&gt;Transaction locking and row versioning guide&lt;/a&gt; &amp;lt;&amp;ndash; A much longer read&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="find-more-from-the-dear-sql-dba-podcast-and-jeremiah-peschka"&gt;Find more from the Dear SQL DBA Podcast and Jeremiah Peschka&lt;/h2&gt;
&lt;p&gt;This is Episode 78 of the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;Dear SQL DBA Podcast&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Read more from Jeremiah Peschka at &lt;a href="https://www.facility9.com/"&gt;facility9.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Dear SQL DBA - Advice for Technical Leaders with Alex Robson</title><link>https://kendralittle.com/2023/08/31/dear-sql-dba-advice-for-technical-leaders-alex-robson/</link><pubDate>Thu, 31 Aug 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/31/dear-sql-dba-advice-for-technical-leaders-alex-robson/</guid><description>&lt;p&gt;Ever wondered what it&amp;rsquo;s like to be a VP or Director of Engineering? I chatted with Alex Robson about leadership in technology, what you can get out of coaching or an MBA program (should you be interested), and what makes a high performing team.&lt;/p&gt;
&lt;p&gt;Alex&amp;rsquo;s site and blog: &lt;a href="https://robsonconsulting.services"&gt;https://robsonconsulting.services&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="my-chat-with-alex-robson"&gt;My chat with Alex Robson&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Ut0aLET0YgU?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="alexs-content-recommendations"&gt;Alex&amp;rsquo;s content recommendations&lt;/h2&gt;
&lt;p&gt;Alex shared these recommendations:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I believe Camille Fournier and Will Larson are wonderful writers with invaluable insights and advice.&lt;/p&gt;
&lt;p&gt;For product thinking, I recommend folks read The Lean Startup by Eric Ries, Principles of Lean Product Development Flow by Don Reinertsen, Safer Sooner Happier by Jonathan Smart, and Accelerate by Dr. Nicole Forsgren.&lt;/p&gt;
&lt;p&gt;Be sure to read books on leadership that are outside of engineering. Dan Pink’s Drive and Eliyahu Goldratt’s The Goal are two of my usual recommendations.&lt;/p&gt;
&lt;p&gt;Last but not least - read books that are about human behavior. Both economists and psychologists ask important questions that may help you unlock better ways to relate to and understand others. I love Daniel Kahneman’s Thinking Fast and Slow, and highly recommend Mistakes Were Made (but not by me) by Carol Tavins and Elliot Aronson.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="more-dear-sql-dba"&gt;More Dear SQL DBA&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;episode index&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Msg 195: STRING_SPLIT Is Not a Recognized Built-In Function Name</title><link>https://kendralittle.com/2023/08/25/string_split-is-not-a-recognized-built-in-function-name/</link><pubDate>Fri, 25 Aug 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/25/string_split-is-not-a-recognized-built-in-function-name/</guid><description>&lt;p&gt;Yesterday, I was writing some Transact SQL to dust off the cobwebs. I got confused when I was playing around with the STRING_SPLIT function, and kept getting the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 195, Level 15, State 10, Line 2
&amp;#39;STRING_SPLIT&amp;#39; is not a recognized built-in function name.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I checked my database compatibility level, which must be 130 or higher for the function to be available. My database compatibility level was 160, so that was fine.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/img/banners/peacock-function.png" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;The issue? STRING_SPLIT is a &lt;em&gt;table valued&lt;/em&gt; function. If your syntax uses it as a &lt;em&gt;scalar&lt;/em&gt; function, you will still see a message that it doesn&amp;rsquo;t exist &amp;ndash; but really the issue is that the function exists, but needs to be called with a different syntax.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at some examples.&lt;/p&gt;
&lt;h2 id="check-and-set-your-database-compatibility-level"&gt;Check and set your database compatibility level&lt;/h2&gt;
&lt;p&gt;This query will return the compatibility level for the current database:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compatibility_level&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_NAME&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If your database compatibility level is less than 130, the STRING_SPLIT() built in function won&amp;rsquo;t be available.&lt;/p&gt;
&lt;p&gt;You can read &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-compatibility-level"&gt;documentation on the differences between compat levels&lt;/a&gt;, which is helpful. It&amp;rsquo;s usually a good idea to make any compatibility levels in development environments first and burn them in for a while before making a change in production.&lt;/p&gt;
&lt;p&gt;To update database compatibility level, run a command like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="how-to-not-use-string_split"&gt;How to NOT use STRING_SPLIT&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what I tried to use that didn&amp;rsquo;t work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING_SPLIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING_SPLIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a,b,c&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both of these return the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 195, Level 15, State 10, Line 1
&amp;#39;STRING_SPLIT&amp;#39; is not a recognized built-in function name.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What both of these queries have in common is that I&amp;rsquo;m trying to use the STRING_SPLIT function in the SELECT clause, as if it&amp;rsquo;s a scalar function. However, it&amp;rsquo;s a table valued function, so we need to do this another way.&lt;/p&gt;
&lt;h2 id="examples-of-successfully-using-string_split"&gt;Examples of successfully using STRING_SPLIT&lt;/h2&gt;
&lt;p&gt;You can use STRING_SPLIT with values that are already in a table, or with a list of supplied values.&lt;/p&gt;
&lt;h3 id="string_split-on-a-column-with-apply"&gt;STRING_SPLIT on a column with APPLY&lt;/h3&gt;
&lt;p&gt;For my first query, I want to run the STRING_SPLIT function against the Tags column in the Posts table.&lt;/p&gt;
&lt;p&gt;Since STRING_SPLIT is a table valued function, I can do that with &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql#using-apply"&gt;CROSS APPLY or OUTER APPLY&lt;/a&gt; syntax, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING_SPLIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that I didn&amp;rsquo;t name the column &lt;strong&gt;value&lt;/strong&gt;. As a table valued function, STRING_SPLIT has already pre-defined the names of the columns it returns. The &amp;lsquo;Value&amp;rsquo; column returns substrings after splitting using the specified separator.&lt;/p&gt;
&lt;div class="info-note"&gt;
🤓 &lt;strong&gt;Aside:&lt;/strong&gt; This example query uses the &lt;a href="https://www.brentozar.com/archive/2015/10/how-to-download-the-stack-overflow-database-via-bittorrent/"&gt;StackOverflow2010 dataset&lt;/a&gt;. The &lt;em&gt;tag&lt;/em&gt; column in post uses a more complex delimiter than a single character, but the STRING_SPLIT function only allows a single character to be specified. This presents some extra data cleansing issues if you want to use STRING_SPLIT for this purpose with that data.
&lt;/div&gt;
&lt;p&gt;If you are running SQL Server 2022 or higher, Azure SQL Database, or Azure SQL Managed Instance, you can optionally set the &lt;code&gt;enable_ordinal&lt;/code&gt; parameter to true to return the &amp;ldquo;ordinal&amp;rdquo; column, which indicates the order the substring had in the original string.&lt;/p&gt;
&lt;p&gt;The syntax for that is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ordinal&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING_SPLIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="string_split-on-literal-values"&gt;STRING_SPLIT on literal values&lt;/h3&gt;
&lt;p&gt;The following syntax will return a single column named value with three rows, one row containing each letter in the string:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING_SPLIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a,b,c&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;split_test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I hope these examples save someone a few minutes of confusion.&lt;/p&gt;</description></item><item><title>Dear SQL DBA - Performance Tuning with Erik Darling</title><link>https://kendralittle.com/2023/08/18/dear-sql-dba-performance-tuning-erik-darling/</link><pubDate>Fri, 18 Aug 2023 16:37:14 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/18/dear-sql-dba-performance-tuning-erik-darling/</guid><description>&lt;p&gt;SQL Server performance tuning expert &lt;a href="https://erikdarlingdata.com"&gt;Erik Darling&lt;/a&gt; joins the podcast today to chat about how good queries can go bad and how bad queries can get better.&lt;/p&gt;
&lt;p&gt;He also answers the question on everyone&amp;rsquo;s mind: if he was a database, what database would he be?&lt;/p&gt;
&lt;h2 id="my-chat-with-erik-darling"&gt;My Chat With Erik Darling&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/D28VePvcSJs?start=70?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="good-stuff-from-erik"&gt;Good Stuff From Erik&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Blog: &lt;a href="https://erikdarlingdata.com/blog/"&gt;https://erikdarlingdata.com/blog/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;YouTube: &lt;a href="https://www.youtube.com/@ErikDarlingData"&gt;https://www.youtube.com/@ErikDarlingData&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="more-dear-sql-dba"&gt;More Dear SQL DBA&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;episode index&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>What To Do When They Are Sure It Was The Database... All The Time</title><link>https://kendralittle.com/2023/08/15/database-vibe-check/</link><pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/15/database-vibe-check/</guid><description>&lt;p&gt;It can be tiring to have the database constantly be the Prime Suspect for performance problems.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve had many variations of this conversation over the years:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Something happened, and we&amp;rsquo;re pretty sure it was the database. Again.&amp;rdquo;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/banners/database-vibes.png"
alt="Four panel cartoon titled Database Vibes. A raccoon asks a corgi about a perf problem at noon, they were pretty sure it was the database. The corgi asks if they checked monitoring, because not much was happening then. The raccoon says they are pretty sure it&amp;#39;s the database, it has a vibe. The corgi asks what color they would say the vibe is, and if it has a smell?"&gt;
&lt;/figure&gt;
&lt;h2 id="frequent-vibe-checks-indicate-an-underlying-problem"&gt;Frequent Vibe Checks Indicate an Underlying Problem&lt;/h2&gt;
&lt;p&gt;It can be annoying to be interrupted. Sometimes it feels like everyone is always blaming the database. And sometimes it feels like people simply don&amp;rsquo;t want to do things themselves.&lt;/p&gt;
&lt;p&gt;But usually, there&amp;rsquo;s an underlying problem where people feel like they &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; tell the health of the database without asking a specialist, and probably having to wait for the answer. People don&amp;rsquo;t usually like to wait, they want to get on with their day.&lt;/p&gt;
&lt;p&gt;Does someone asking, &amp;ldquo;hey, was something up with the database?&amp;rdquo; have a way to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review utilization and query runtime for the time in question?&lt;/li&gt;
&lt;li&gt;Check what wait stats were in the time period and compare them to a baseline?&lt;/li&gt;
&lt;li&gt;Check the ​database logs​ for errors or odd messages?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If they have a way to do this, is it easy for them to remember how to do it and access it? Could a custom report or a set of instructions help them run through the process more easily?&lt;/p&gt;
&lt;p&gt;Talk to your questioner about what types of tooling, information, or processes could help them get this information themselves, without having to wait.&lt;/p&gt;
&lt;h2 id="i-dont-have-time-for-that"&gt;I Don&amp;rsquo;t Have Time for That&lt;/h2&gt;
&lt;p&gt;These tools or processes may not be things that you can stop and create immediately, and that&amp;rsquo;s fine.&lt;/p&gt;
&lt;p&gt;When having this discussion, think about yourself as a type of &amp;ldquo;product manager&amp;rdquo; for working with the database. You aren&amp;rsquo;t volunteering to do things, and it&amp;rsquo;s fine to be clear about that. The important thing is to explore and understand your customer&amp;rsquo;s problem, and why it isn&amp;rsquo;t easy for them to do this yourself. That can be valuable information on how your team can work with others better, and can be a cause that you can champion (even if you aren&amp;rsquo;t doing the work yourself) in the future.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also valuable to set expectations clearly. It&amp;rsquo;s great to tell your coworker that your plate is full, and you may not be able to solve their bigger problem immediately, but that you&amp;rsquo;d like to learn more about it so that you can share it with your team.&lt;/p&gt;
&lt;h2 id="but-im-just-a-dba"&gt;But I&amp;rsquo;m Just a DBA&lt;/h2&gt;
&lt;p&gt;More and more, seniority in tech roles isn&amp;rsquo;t purely about coding skills or deep technical knowledge. It&amp;rsquo;s also about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding your customers, their pain points, and why they choose specific tools and processes.&lt;/li&gt;
&lt;li&gt;Advocating for ways to help your customers work better, and including them in relevant conversations so they can advocate for themselves.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Leading up&amp;rdquo; and get time allocated to get work done for your customers&amp;ndash; even if you aren&amp;rsquo;t doing it yourself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, situations like this are truly opportunities.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t get trapped in thinking that your value is in being the one to manually answer these questions as they come up on an individual basis. There&amp;rsquo;s an even greater value you can give in helping equip people to answer these questions themselves! Don&amp;rsquo;t worry&amp;ndash; there will always be harder questions that they will come back to you for later.&lt;/p&gt;
&lt;p&gt;No matter how hard you try to automate yourself out of a job, in my experience it only helps your career.&lt;/p&gt;</description></item><item><title>Dear SQL DBA: Tech Interviews in 2023 With Jeremiah Peschka</title><link>https://kendralittle.com/2023/08/11/dear-sql-dba-tech-interviews-jeremiah-peschka/</link><pubDate>Fri, 11 Aug 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/11/dear-sql-dba-tech-interviews-jeremiah-peschka/</guid><description>&lt;p&gt;Tech interviews are weird and wacky. How did they get this way, and how SHOULD they be? Jeremiah Peschka joins us to discuss.&lt;/p&gt;
&lt;p&gt;Thanks to Jeremiah for being the first guest on my podcast! It only took &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;75 episodes&lt;/a&gt; before I had a guest.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/rTIw6EXNpzQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="more-from-jeremiah-peschka"&gt;More From Jeremiah Peschka&lt;/h2&gt;
&lt;p&gt;Jeremiah&amp;rsquo;s blog is &lt;a href="https://www.facility9.com/"&gt;facility9.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="more-dear-sql-dba"&gt;More Dear SQL DBA&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;episode index&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Database DevOps Core Concepts: Migration Scripts</title><link>https://kendralittle.com/2023/08/09/database-devops-core-concepts-migration-scripts/</link><pubDate>Wed, 09 Aug 2023 10:52:03 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/09/database-devops-core-concepts-migration-scripts/</guid><description>&lt;p&gt;Database migration scripts are a popular and effective way to check database code into version control.&lt;/p&gt;
&lt;p&gt;In this post I describe the most common features of popular migration script runners for database code deployment, along with the top gotchas that folks hit when versioning their database code with migrations.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/img/banners/raccoon-laptop-waving.png"
alt="A raccoon character waving from behind a laptop computer" width="240"&gt;
&lt;/figure&gt;
&lt;h2 id="benefits-of-migration-scripts-for-database-devops"&gt;Benefits of Migration Scripts for Database DevOps&lt;/h2&gt;
&lt;p&gt;Migration scripts enable checking database code into version control in a human readable format. This provides a centralized, standard way to record all changes.&lt;/p&gt;
&lt;p&gt;Migration scripts are also useful to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement Continuous Integration processes for database code / automate validation of changes to the code.&lt;/li&gt;
&lt;li&gt;Automate change deployment in both development and production environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, these benefits bring database code into line with processes and standards for application code.&lt;/p&gt;
&lt;h2 id="common-tools-used-with-a-migrations-approach"&gt;Common Tools Used With a Migrations Approach&lt;/h2&gt;
&lt;p&gt;Database migration scripts for change deployment are used by tools like Flyway and Liquibase. Some companies write custom implementations of migration script runners.&lt;/p&gt;
&lt;p&gt;If you are evaluating building or buying one of these toolsets, this post will help you understand essential functionality and which workflows to tackle first.&lt;/p&gt;
&lt;h2 id="essential-functionality-for-database-migration-scripts"&gt;Essential Functionality for Database Migration Scripts&lt;/h2&gt;
&lt;p&gt;Core functionality to consider when adopting or writing a database migration script runner are versioned migration scripts that can be run in a defined order, a way to track migration script status against a specific target database to run scripts only when needed, baseline scripts, and re-runnable migrations.&lt;/p&gt;
&lt;h3 id="what-are-database-migrations-or-migration-scripts"&gt;What Are Database &amp;ldquo;Migrations&amp;rdquo; or &amp;ldquo;Migration Scripts&amp;rdquo;?&lt;/h3&gt;
&lt;p&gt;A database migration script changes the state of your database, most commonly by adding, modifying, or deleting objects in the database.&lt;/p&gt;
&lt;p&gt;Migration scripts can also add or modify data in objects in the database. An example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We start with an empty database.&lt;/li&gt;
&lt;li&gt;Our first migration script creates a table for bananas and inserts rows.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bananas&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_bananas&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;banana_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bananas&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_color&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Cavendish&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Yellow&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Plantain&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Green&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Red Dacca&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Red&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Manzano&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Yellow&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Burro&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Yellow&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="info-note"&gt;
ℹ️ &lt;strong&gt;Info:&lt;/strong&gt; I didn't include any error handling in this code. Some tooling helps with that automatically, some does not.
&lt;/div&gt;
&lt;p&gt;The main reason I show this code is: it&amp;rsquo;s just that simple! Migration scripts can be written in a variety of languages, depending on what the migration script runner supports, but generally these are scripts written in plain SQL that are easy for humans to review.&lt;/p&gt;
&lt;h3 id="migration-scripts-are-numbered-and-run-in-order"&gt;Migration Scripts Are Numbered and Run in Order&lt;/h3&gt;
&lt;p&gt;Our second migration creates a table for banana ratings. This table uses banana_id values that are defined in dbo.bananas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;banana_ratings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rating_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;banana_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rating_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rating_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FK_BananaRating_Banana&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOREIGN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;banana_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REFERENCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bananas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;banana_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second migration script has a foreign key dependency on the first migration. They need to always run in a specific order.&lt;/p&gt;
&lt;p&gt;Migration runners commonly provide a way to number scripts and execute them in the desired order.&lt;/p&gt;
&lt;h3 id="migration-script-status"&gt;Migration Script Status&lt;/h3&gt;
&lt;p&gt;The log tracking which migration scripts have been run with their status is often kept in a table in the target database.&lt;/p&gt;
&lt;p&gt;The migration script runner generally reads from this table prior to a deployment, and updates the table as the deployment progresses.&lt;/p&gt;
&lt;h3 id="baseline-script"&gt;Baseline Script&lt;/h3&gt;
&lt;p&gt;What if you need to start with a database with existing objects?&lt;/p&gt;
&lt;p&gt;A &amp;ldquo;baseline&amp;rdquo; migration script contains all of the definitions of objects in the database, ordered so that dependencies can be met. This is generally contained in a single migration script with a special status to differentiate it from &amp;ldquo;normal&amp;rdquo; migrations.&lt;/p&gt;
&lt;p&gt;Migration script runners usually only deploy the baseline script to an empty target database. This allows validation of database code for continuous integration.&lt;/p&gt;
&lt;h3 id="re-runnable-migrations"&gt;Re-Runnable Migrations&lt;/h3&gt;
&lt;p&gt;Sometimes you want a migration to run every time you deploy changes. This might ensure the target database is configured for the appropriate environment (dev, prod, etc), create objects like stored procedures, or ensure that an object or data is in a specific state.&lt;/p&gt;
&lt;p&gt;Migration runners sometimes allow specific naming and ordering conventions for re-runnable migration scripts.&lt;/p&gt;
&lt;h2 id="what-gets-tricky"&gt;What Gets Tricky?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a lot that can get complex when you get into the weeds. The top places where folks get confused are related to rollbacks, shared database environments, and dealing with changes in deployment order/numbering challenges.&lt;/p&gt;
&lt;h3 id="rollbacks"&gt;Rollbacks&lt;/h3&gt;
&lt;p&gt;Some tools have options for Rollback scripts, but managing them is complex. In production, you usually want every migration recorded as a &amp;ldquo;roll forward&amp;rdquo; because it&amp;rsquo;s a real deployment, and you want your future builds to play out the same sequence.&lt;/p&gt;
&lt;p&gt;Also, everyone hates writing rollbacks manually. Everyone.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/img/banners/messed-up-trash-can.png"
alt="A cartoon illustration of a messy trash can, representing the complexity of rollback scripts" width="500"&gt;
&lt;/figure&gt;
&lt;h3 id="shared-database-environments"&gt;Shared Database Environments&lt;/h3&gt;
&lt;p&gt;Mistakes or necessary changes to scripts are often identified in shared testing or pre-production environments.&lt;/p&gt;
&lt;p&gt;If there is no automated, fast way to reset the database (including all its data), then it can be time consuming to validate that the target environment is in the desired state once code is rolled back and scripts are modified.&lt;/p&gt;
&lt;h3 id="numbering-while-integrating-changes-from-multiple-teams"&gt;Numbering While Integrating Changes From Multiple Teams&lt;/h3&gt;
&lt;p&gt;Code is often not deployed to prod in the same order it is completed.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say Ravi writes migration script 42, which needs a lot of testing. Sandy releases an important hotfix in migration 43. Now Ravi&amp;rsquo;s script is out of order. Should they renumber it? What does that mean for all environments where it has already been deployed? What does this mean for future &amp;ldquo;from scratch&amp;rdquo; builds?&lt;/p&gt;
&lt;h2 id="enhancing-a-migrations-approach-with-state-comparisons-and-auto-generated-code"&gt;Enhancing a Migrations Approach With State Comparisons and Auto-Generated Code&lt;/h2&gt;
&lt;p&gt;Database &amp;ldquo;state&amp;rdquo; capture and comparison tools can augment migration script approaches with cool functionality. Vendors often provide this as part of their value proposition.&lt;/p&gt;
&lt;p&gt;Those writing rollback scripts will want to use generative AI to help draft and validate changes. Both humans and AI can write bad SQL, so be wise how you use both.&lt;/p&gt;
&lt;h2 id="the-value-of-getting-database-code-into-version-control-is-worth-the-work"&gt;The Value of Getting Database Code Into Version Control Is Worth the Work&lt;/h2&gt;
&lt;p&gt;Thinking about the gotchas can be daunting. There is a lot to gain even if some portions of your process remain manual, or if you implement automation in stages. A recap of the benefits of database migrations is worth it at this point.&lt;/p&gt;
&lt;p&gt;These will give you the ability for many good things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clear audit trail of development and deployment code&lt;/li&gt;
&lt;li&gt;Lower likelihood of losing work or accidental deployments&lt;/li&gt;
&lt;li&gt;Continuous Integration&lt;/li&gt;
&lt;li&gt;Less or very limited manual work in deployments&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Dear SQL DBA - Data Roles: DBA, DBRE, and Data Engineer</title><link>https://kendralittle.com/2023/08/04/dear-sql-dba-data-roles-dba-dbre-de/</link><pubDate>Fri, 04 Aug 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/08/04/dear-sql-dba-data-roles-dba-dbre-de/</guid><description>&lt;p&gt;There are lots of jobs for data folks. In this episode, I discuss three hot job titles: Database Administrator (DBA), Database Reliability Engineer (DBRE), and Data Engineer (DE).&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/loziSHptDWY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="as-explained-by-trash"&gt;As Explained by Trash&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/free-sql-comics/data-roles-dba-dbre-de-venn-diagram-trash.png"
alt="A humorous Venn diagram showing the overlap between DBA, DBRE, and Data Engineer roles with a trash-themed illustration" width="700"&gt;
&lt;/figure&gt;
&lt;h2 id="a-bit-more-professionally"&gt;A Bit More Professionally&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/img/free-sql-comics/data-roles-dba-dbre-de-venn-diagram.png"
alt="A professional Venn diagram illustrating the overlap between Database Administrator (DBA), Database Reliability Engineer (DBRE), and Data Engineer (DE) roles"&gt;
&lt;/figure&gt;
&lt;h2 id="more-dear-sql-dba"&gt;More Dear SQL DBA&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href="https://kendralittle.com/dear-sql-dba-podcast"&gt;episode index&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Why Not Call Database DevOps Simply DevOps?</title><link>https://kendralittle.com/2023/07/28/what-is-database-devops/</link><pubDate>Fri, 28 Jul 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/07/28/what-is-database-devops/</guid><description>&lt;p&gt;Sometimes people are annoyed by the term &amp;lsquo;Database DevOps&amp;rsquo;. Why not call it simply &amp;lsquo;DevOps&amp;rsquo;? After all, Database DevOps follows the same core principles.&lt;/p&gt;
&lt;p&gt;The answer is simple: implementing DevOps is tricky by itself, but most teams are set up to fail when it comes to implementing DevOps for databases. This makes it worth defining as a specialization.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/img/banners/database-devops.png"
alt="Database DevOps banner illustration" width="240"&gt;
&lt;/figure&gt;
&lt;h2 id="what-is-devops"&gt;What is DevOps?&lt;/h2&gt;
&lt;p&gt;
&lt;a href="https://www.donovanbrown.com/post/what-is-devops" target="_blank"&gt;Donovan Brown defines DevOps&lt;/a&gt;
as &amp;ldquo;the union of people, process, and products to enable continuous delivery of value to our end users.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Donovan&amp;rsquo;s definition encapsulates the essence of what DevOps aims to achieve: an emphasis that people are essential, a focus on collaborative processes, and the importance of tooling and automation with the goal to continuously deliver value all the way to the customers who use it.&lt;/p&gt;
&lt;p&gt;As Donovan writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is very important to realize that DevOps is not a product. You cannot buy DevOps and install it. DevOps is not just automation or infrastructure as code. DevOps is people following a process enabled by products to deliver value to our end users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-is-database-devops-uniquely-difficult"&gt;Why is Database DevOps Uniquely Difficult?&lt;/h2&gt;
&lt;p&gt;I generally see three major challenges with teams implementing DevOps for Database code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Data is stateful. Blue/Green (sometimes called Red/Black) deployment models don&amp;rsquo;t generally work for database code, as data may be lost by returning to the state of the data before deployment began. This adds significant complexity to finding the right products and building the right processes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Key stakeholders get quite nervous. Data loss or data breaches are incredibly expensive and damaging for brands. This has led to much more rigid change management practices when it comes to deploying changes to databases, especially in more regulated industries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DBAs and Developers are historically misaligned. Database Administrators (DBAs) are often not deeply familiar with tooling and practices that make implementing devops safer. DBAs are often trained to act as the &amp;ldquo;protectors&amp;rdquo; of production environments, as well, and to look for everything that might possibly go wrong. This positioning of the DBA role creates significant friction between DBAs and development and DevOps teams, and makes it much harder for these teams to co-create new processes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Not everyone has all three of these challenges. Sometimes significant cultural groundwork has been laid and DBA and Development teams are aligned on a strategy. This is somewhat rare, however.&lt;/p&gt;
&lt;p&gt;I more often see teams who are successful with Database DevOps because there is only a development team or only a DBA team involved: this tends to make things simpler because of the lack of friction that cross-team collaboration can create. However, in these cases there is often a lack of specialized knowledge that would enrich the process because a key team is missing.&lt;/p&gt;
&lt;p&gt;But still, the first two challenges of stateful data and wary stakeholders are nearly ever-present and take significant work to manage.&lt;/p&gt;
&lt;h2 id="avoid-the-pitfalls-of-database-devops"&gt;Avoid the Pitfalls of Database DevOps&lt;/h2&gt;
&lt;p&gt;While these guidelines can apply to any kind of DevOps initiative, they are especially critical when it comes to databases.&lt;/p&gt;
&lt;h2 id="1-spend-a-lot-of-time-carefully-scoping-your-mvp"&gt;1. Spend a lot of time carefully scoping your MVP&lt;/h2&gt;
&lt;p&gt;The biggest mistake that I see folks make is trying to ensure they can solve the very hardest problems with stateful data at the very beginning. This often takes the form of, &amp;ldquo;we need to make sure we can fully automate rollbacks for every problem in 30 seconds in production.&amp;rdquo; Because of the nature of stateful data, different business requirements, and implications of different data architectures, there is no One-Size Fits All approach to this. Even if you solve this for one database, that doesn&amp;rsquo;t mean you can cut and paste the same approach to others in your organization. Teams can find this hugely disheartening.&lt;/p&gt;
&lt;p&gt;The truth is, there is huge value to simply getting your database code into version control. Automating deployments to dev environments and finding ways to reset those environments automatically also will raise the quality of your code and empower developers to work faster. There are a variety of ways to scope your MVP and plan implementations, and it&amp;rsquo;s important to carefully identify the right one for your teams.&lt;/p&gt;
&lt;h2 id="2-talk-about-guardrails-early-and-often-to-stakeholders"&gt;2. Talk About Guardrails Early and Often to Stakeholders&lt;/h2&gt;
&lt;p&gt;One pitfall I see is folks focussing too much on avoiding failures as the major benefit of DevOps for databases.&lt;/p&gt;
&lt;p&gt;Things are going to break. DevOps can help you identify failures earlier in your process and mitigate risk, but implementing the right processes and the right tooling to do this, while getting folks on board to collaboratively build those processes is an iterative effort. There will be errors, there will be failures.&lt;/p&gt;
&lt;p&gt;A strategy that helps with this is the concept of guardrails. If you don&amp;rsquo;t like that term, you can also talk about safety. The important thing to note is that guardrails&amp;ndash; aka safety checks&amp;ndash; can be implemented in a variety of ways. Automation is great, but takes time to build. Start with human-powered checks first. Make these human checks stronger, more resilient, and use the information you learn to prioritize how to automate these iteratively.&lt;/p&gt;
&lt;p&gt;This will take time. It&amp;rsquo;s important to plan this time into your effort from the beginning, and ensure that leadership is aware that regular investment in the process over time will be required.&lt;/p&gt;
&lt;h2 id="3-culture"&gt;3. Culture&lt;/h2&gt;
&lt;p&gt;A lot of the hardest problems with Database DevOps are not technical: they are human problems. Database administrators in particular can be highly skeptical of change. I know many DBAs and DBREs (Database Reliability Engineers) who rigidly cling to the identity of the Protector of the Data.&lt;/p&gt;
&lt;p&gt;As these data folks see it, developers who aren&amp;rsquo;t experts on the database they are using are just going to mess things up &amp;ndash; but it&amp;rsquo;s the DBA or DBRE who is going to get blamed and have to clean up the mess.&lt;/p&gt;
&lt;p&gt;But you know what? This point of view didn&amp;rsquo;t come from nowhere. This perspective has been set in IT culture for a long time and is still continually reinforced by tech leadership in subtle ways. There is some truth in this perspective.&lt;/p&gt;
&lt;p&gt;For many of these teams, many conversations and a lot of listening to concerns are needed to open up possibilities for change. Bridging the gaps between other teams may take significant work as well. Teams need to be brought together in a way that they can effectively teach and learn from one another.&lt;/p&gt;
&lt;h2 id="database-devops-is-worth-the-investment"&gt;Database DevOps Is Worth the Investment&lt;/h2&gt;
&lt;p&gt;The payoff goes back to
&lt;a href="https://www.donovanbrown.com/post/what-is-devops" target="_blank"&gt;Donovan Brown's definition of DevOps&lt;/a&gt;
: continuous delivery of value to your end users.&lt;/p&gt;
&lt;p&gt;Delivering value to your customers continually can be the difference between success and failure of products and entire companies. Don&amp;rsquo;t let your databases be the gating factor in your organization&amp;rsquo;s success.&lt;/p&gt;</description></item><item><title>The Difference Between DBAs, DBREs, and Data Engineers</title><link>https://kendralittle.com/2023/07/26/data-careers-dba-dbre-data-engineer/</link><pubDate>Wed, 26 Jul 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/07/26/data-careers-dba-dbre-data-engineer/</guid><description>&lt;p&gt;Twenty years ago, database administrators (DBAs) were the primary career path when it came to specializing in data management.&lt;/p&gt;
&lt;p&gt;Much has changed: development patterns transformed from Waterfall to Agile, DevOps drives automation and shared ownership of code, and cloud services have made &lt;strong&gt;many&lt;/strong&gt; more kinds of PaaS databases, data lakes, and data lakehouses available to organizations of all sizes.&lt;/p&gt;
&lt;p&gt;These changes have introduced new and varied career paths for data folks which have different emphases on skill sets. In this post, I talk through the commonalities and differences between DBAs, Database Reliability Engineers (DBREs), and Data Engineers (DEs). Whether you&amp;rsquo;re a hiring manager or data professional, it&amp;rsquo;s worth knowing about these roles.&lt;/p&gt;
&lt;h2 id="why-does-it-matter"&gt;Why does it matter?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/dba-dbre-data%20engineer.png"
alt="Venn diagram comparing DBA, DBRE, and Data Engineer roles" width="250"&gt;
&lt;/figure&gt;
&lt;p&gt;We all know that job titles can be meaningless &amp;ndash; I once was a DBA with the job title of &amp;ldquo;Software Development Engineer, Testing,&amp;rdquo; because of an HR categorization issue. (Did I develop software? No. Did I write tests? Also no.)&lt;/p&gt;
&lt;p&gt;However, I think these concepts are useful to think about for a few reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Defining yourself and planning your career using a common language can be useful in broadening your horizons.&lt;/li&gt;
&lt;li&gt;When writing job descriptions, these terms are useful keywords to get the job in front of the best candidates.&lt;/li&gt;
&lt;li&gt;For job candidates, understanding the breadth of these disciplines is useful when reviewing opportunities. It&amp;rsquo;s a red flag when any position requires an individual who covers &lt;em&gt;all&lt;/em&gt; of the roles that I describe here with significant breadth. While it&amp;rsquo;s certainly possible to dip your toe into multiple areas, covering all three of these specialties deeply is unmanageable.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-trash-can-explanation"&gt;The trash can explanation&lt;/h2&gt;
&lt;p&gt;I asked folks on social media what they think about these three roles. One of my favorite responses came from &lt;a href="https://erikdarlingdata.com/"&gt;Erik Darling&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/erik-darling-trash-cans.png"
alt="Tweet with the words &amp;#39;No one can actually tell them apart but everyone blames them when the trash cans are knocked over." width="550"&gt;
&lt;/figure&gt;
&lt;p&gt;Maybe it&amp;rsquo;s just that my first DBA job came with the team motto of &amp;lsquo;Data Janitors&amp;rsquo;, but this resonated with me. It can all be described by trash.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/data-roles-dba-dbre-de-venn-diagram-trash.png"
alt="Venn diagram. All areas overlap with trash. DBAs are concerned with individual dumpsters. DBREs are concerned with thousands of trash containers. DEs are concerned with lakes of trash juice and streaming trash." width="800"&gt;
&lt;/figure&gt;
&lt;h2 id="the-business-explanation"&gt;The business explanation&lt;/h2&gt;
&lt;p&gt;Although trash cans are easy to relate to, they don&amp;rsquo;t necessarily help you much in a job interview. Here&amp;rsquo;s a more specific version of how I&amp;rsquo;ve seen these roles compare in job postings, and in organizations I&amp;rsquo;ve worked with as an FTE, external speaker, or consultant.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This image is too complex for alt text, but the content is explained in the paragraphs below the image.&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/data-roles-dba-dbre-de-venn-diagram.png"
alt="Detailed Venn diagram showing the overlap and differences between DBA, DBRE, and Data Engineer roles with specific skill sets and responsibilities" width="800"&gt;
&lt;/figure&gt;
&lt;h2 id="commonalities-between-dbas-dbres-and-des"&gt;Commonalities between DBAs, DBREs, and DEs&lt;/h2&gt;
&lt;p&gt;There are a few core specialties between all three of these roles, although they are used in different contexts. All of these roles are concerned with how data is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stored&lt;/li&gt;
&lt;li&gt;Secured&lt;/li&gt;
&lt;li&gt;Shared&lt;/li&gt;
&lt;li&gt;Backed up&lt;/li&gt;
&lt;li&gt;Queried&lt;/li&gt;
&lt;li&gt;Archived&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For an example of &amp;ldquo;contexts&amp;rdquo;, I mean that a DBA may be thinking about how this applies to data in a relational database. A DBRE may be thinking about how these tasks are automated across both on-prem and cloud environments, with multiple types of data stores. Meanwhile a DE may be thinking about how this applies in a Lakehouse or Event Streaming scenario.&lt;/p&gt;
&lt;p&gt;In other words, everyone cares about compliance, data loss, security, and availability in one way or another.&lt;/p&gt;
&lt;p&gt;DBAs, DBREs, and DEs all generally know and use &lt;strong&gt;SQL&lt;/strong&gt; on a regular basis.&lt;/p&gt;
&lt;h2 id="database-administrator-key-strengths"&gt;Database Administrator key strengths&lt;/h2&gt;
&lt;p&gt;Database Administrators are often highly knowledgeable regarding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Relational databases (mostly OLTP)&lt;/li&gt;
&lt;li&gt;Bespoke query tuning and performance troubleshooting&lt;/li&gt;
&lt;li&gt;Scaling monoliths&lt;/li&gt;
&lt;li&gt;Patching and upgrades (often semi-automated)&lt;/li&gt;
&lt;li&gt;Environment standardization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are the folks who are most likely to learn 1,001 configuration settings for a specific database technology, along with the pros and cons of using each setting, alone or in conjunction with one another.&lt;/p&gt;
&lt;p&gt;While DBAs often implement automation, often writing bespoke scripts is a small part of their job and much of the focus is on adopting off-the-shelf or open source automation tools written by others. Establishing reliable processes is an emphasis and &amp;ldquo;protecting&amp;rdquo; data in source databases is an emphasis.&lt;/p&gt;
&lt;h2 id="database-reliability-engineer-key-strengths"&gt;Database Reliability Engineer key strengths&lt;/h2&gt;
&lt;p&gt;The DBRE role focuses on automation as well as empowering developers to have shared ownership of code. While DBAs are generally &amp;ldquo;protectors&amp;rdquo; of data, DBREs have a mission of helping lay down safe and flexible guardrails for data that allows development to move faster and more flexibly.&lt;/p&gt;
&lt;p&gt;DBREs key strengths are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data related infrastructure as code (IaC)&lt;/li&gt;
&lt;li&gt;Automated cost monitoring, availability monitoring, performance monitoring at scale&lt;/li&gt;
&lt;li&gt;Turning &amp;ldquo;pets&amp;rdquo; into &amp;ldquo;cattle&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Enabling developers to own and support their own data code&lt;/li&gt;
&lt;li&gt;Data code versioning, testing, and automated deployments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to SQL, DBREs use various command line and scripting languages for automation.&lt;/p&gt;
&lt;h2 id="data-engineer-key-strengths"&gt;Data Engineer key strengths&lt;/h2&gt;
&lt;p&gt;The Data Engineer role often interfaces with Enterprise Reporting and Data Scientist teams. Data Engineers generally load, wrangle, and help manage vast amounts of data from a large variety of sources within an Enterprise.&lt;/p&gt;
&lt;p&gt;You might want to be a Data Engineer if the following excite you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data lakes, lakehouses, warehouses: architecture and implementation&lt;/li&gt;
&lt;li&gt;Data pipelines, transformations, data quality checks&lt;/li&gt;
&lt;li&gt;Streaming architectures&lt;/li&gt;
&lt;li&gt;Governance, metadata, lineage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Data Engineers often use Python quite a lot, sometimes more than they use SQL. Like DBREs, they have a focus on using version control and automating testing and deployments, although this is more related to notebooks, data pipelines, and transformation (as compared to Terraform or Bicep deployments and automating monitoring).&lt;/p&gt;
&lt;h2 id="when-interviewing-ask-what-these-terms-mean-to-the-employer"&gt;When interviewing, ask what these terms mean to the employer&lt;/h2&gt;
&lt;p&gt;I recently saw a conversation online between Data Engineers discussing that the Data Engineer role is defined quite differently at Meta than at Google, which can make for an awkward interview for candidates who assume that expectations for the role are similar.&lt;/p&gt;
&lt;p&gt;This is true for any role, really. It&amp;rsquo;s always worth asking in a job interview: what are the primary pain points you want this person to solve? What are the key strengths that a candidate will need to succeed in this role?&lt;/p&gt;
&lt;h2 id="whats-your-take"&gt;What&amp;rsquo;s your take?&lt;/h2&gt;
&lt;p&gt;What have I missed? How are your definitions different? Tell me in the comments, or write your own post and share a link.&lt;/p&gt;</description></item><item><title>Should We Do Index Maintenance on an Azure SQL Managed Instance or Azure SQL Database?</title><link>https://kendralittle.com/2023/07/17/should-i-do-index-maintenance-azure-sql-managed-instance/</link><pubDate>Mon, 17 Jul 2023 08:38:02 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/07/17/should-i-do-index-maintenance-azure-sql-managed-instance/</guid><description>&lt;p&gt;Have you ever received advice that was technically correct, but it was too hard to understand?&lt;/p&gt;
&lt;p&gt;I think of this as &amp;ldquo;accidental bad advice,&amp;rdquo; because it can lead to confusion and bad outcomes. There&amp;rsquo;s a LOT of accidental bad advice out there on index maintenance for SQL Server and cloud versions like Azure SQL, even in the official documentation.&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;m answering a common index maintenance question, and we&amp;rsquo;re going to keep it simple.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Unicorn-cloud.png"
alt="A unicorn illustration representing Azure SQL cloud services" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="do-we-need-index-maintenance-if-we-have-fast-storage"&gt;Do We Need Index Maintenance If We Have Fast Storage?&lt;/h2&gt;
&lt;p&gt;Last week I received a question about whether index maintenance was needed for an Azure SQL Managed instance or Azure SQL Database, given that the documentation says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For most types of storage used in Azure SQL Database and Azure SQL Managed Instance, there is no difference in performance between sequential I/O and random I/O. This reduces the impact of index fragmentation on query performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Source: &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes"&gt;Optimize index maintenance to improve query performance and reduce resource consumption&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Essentially, this is saying that often Azure SQL uses SSD for physical storage. It implies that therefore index maintenance isn&amp;rsquo;t very useful. A reader would be easily tempted to use this sentence to justify not setting up the maintenance at all.&lt;/p&gt;
&lt;h2 id="yes-we-need-index-maintenance-but-tune-it-to-do-the-minimum"&gt;Yes, We Need Index Maintenance, but Tune It to Do the Minimum&lt;/h2&gt;
&lt;p&gt;Even if you have very fast storage, if you don&amp;rsquo;t ever do index maintenance then you can end up with problems such as a lot of empty space in an index.&lt;/p&gt;
&lt;p&gt;This is no big deal on small indexes (think less than 300MB to keep it simple) but can slow down performance on larger indexes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In consulting it isn&amp;rsquo;t uncommon for me to find 20+ GB of empty space in larger databases when index maintenance hadn&amp;rsquo;t been implemented.&lt;/li&gt;
&lt;li&gt;Think of this space as both disk space and space in &lt;em&gt;memory&lt;/em&gt;. That means you can fit less in memory!&lt;/li&gt;
&lt;li&gt;Memory is especially expensive in Azure SQL Managed Instance and Azure SQL Database. It&amp;rsquo;s kinda shocking how little you get for how much you pay, really.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But if you overdo index maintenance, then you are wasting CPU resources and can slow down concurrent activities.&lt;/p&gt;
&lt;p&gt;So it&amp;rsquo;s a good general rule to have index maintenance, but to tune the maintenance to only do the minimum.&lt;/p&gt;
&lt;p&gt;At this point, someone might say: &amp;ldquo;But Kendra, the documentation essentially says that after the quote!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Sure, the official guidance says this. It says this so verbosely and in such excruciating detail that I must force myself to read the full page. Would I understand it if I didn&amp;rsquo;t have years of foundational knowledge on the topic? Probably not.&lt;/p&gt;
&lt;h2 id="how-do-we-make-index-maintenance-do-the-minimum"&gt;How Do We Make Index Maintenance Do the Minimum?&lt;/h2&gt;
&lt;p&gt;Like loads of folks, I&amp;rsquo;m a big fan of Ola Hallengren&amp;rsquo;s free &lt;a href="https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html"&gt;SQL Server Index and Statistics Maintenance solution&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This tool should work for Azure SQL Managed Instance like it does for a SQL Server hosted on a VM, container, or server. It should also work on Amazon RDS.&lt;/p&gt;
&lt;p&gt;For Azure SQL Database, &amp;ldquo;You need to &lt;a href="https://ola.hallengren.com/downloads.html"&gt;download&lt;/a&gt; the objects as separate scripts&amp;rdquo; and come up with your own way to automate execution for them. (&lt;a href="https://ola.hallengren.com/frequently-asked-questions.html"&gt;Source&lt;/a&gt;). One way to do this is via Azure Data Factory: &lt;a href="https://youtu.be/yZl_x39nizE"&gt;Daniel Taylor explains how to set it up in this video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Azure SQL supports online index operations for both Managed Instance and Database. Assuming your database may be queried during maintenance, here&amp;rsquo;s a sample command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IndexOptimize&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Databases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;USER_DATABASES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;MinNumberOfPages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;FragmentationLow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;FragmentationMedium&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INDEX_REORGANIZE, INDEX_REBUILD_ONLINE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;FragmentationHigh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INDEX_REBUILD_ONLINE, INDEX_REORGANIZE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;FragmentationLevel1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;FragmentationLevel2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;LogToTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s walk through these parameters at a high level. For more details, check &lt;a href="https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html"&gt;Ola&amp;rsquo;s docs (which are great)&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Databases &amp;ndash; this will loop through all user databases. You can specify an individual database, use wildcards, and do much more.&lt;/li&gt;
&lt;li&gt;MinNumberOfPages &amp;ndash; this defaults to 1000 pages, or 7.85MB. That&amp;rsquo;s REAL small to me on modern storage. To skip smaller indexes, I suggest raising this up to 40000 pages, which is ~313MB.&lt;/li&gt;
&lt;li&gt;FragmentationLevel1 and FragmentationLevel2 &amp;ndash; I agree with &lt;a href="https://www.brentozar.com/archive/2014/12/tweaking-defaults-ola-hallengrens-maintenance-scripts/"&gt;Brent Ozar&amp;rsquo;s suggested limits of 50% and 80%&lt;/a&gt; as general starter levels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="do-you-have-index-maintenance-questions"&gt;Do You Have Index Maintenance Questions?&lt;/h2&gt;
&lt;p&gt;Feel free to ask away in the comments&amp;ndash; small questions we can probably answer directly. Big questions might get their own post!&lt;/p&gt;</description></item><item><title>Even Smart People Make Terrible Data Modeling Decisions</title><link>https://kendralittle.com/2023/07/11/smart-people-make-bad-data-modeling-decisions/</link><pubDate>Tue, 11 Jul 2023 09:28:46 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/07/11/smart-people-make-bad-data-modeling-decisions/</guid><description>&lt;p&gt;I was doing a bit of data analysis, and the resulting numbers didn&amp;rsquo;t quite add up.&lt;/p&gt;
&lt;p&gt;I double-checked my queries. Had I goofed in my sql? Nope. Next, I looked into if some of the data was in an inconsistent state.&lt;/p&gt;
&lt;p&gt;What I found was worse than what I&amp;rsquo;d imagined. As a data person, it made me feel sad and icky.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/horrified-raccoon.png"
alt="A horrified raccoon character expressing shock at discovering bad data modeling decisions" width="250"&gt;
&lt;/figure&gt;
&lt;p&gt;That&amp;rsquo;s because it&amp;rsquo;s usually not too hard to clean up bad data. It&amp;rsquo;s almost always &lt;strong&gt;much&lt;/strong&gt; harder to fix a badly designed data model which is already established in production.&lt;/p&gt;
&lt;h2 id="the-schema"&gt;The Schema&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m anonymizing the schema here, because it doesn&amp;rsquo;t matter who did this. Badly designed relational databases are very, very common&amp;ndash; this one made me feel a certain way because it&amp;rsquo;s &lt;em&gt;uniquely&lt;/em&gt; bad, but it&amp;rsquo;s certainly not the worst thing anyone&amp;rsquo;s ever done to a database. It was simply pernicious.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s say we have a table with many millions of rows, named Widgets. Widgets is primarily a table in an OLTP database, the but database is also used for lots of analytics.&lt;/p&gt;
&lt;p&gt;Widgets has many columns, but among them are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WidgetId, a surrogate key that uniquely identifies every widget in the table.&lt;/li&gt;
&lt;li&gt;WidgetTypeId, which joins to WidgetTypes.&lt;/li&gt;
&lt;li&gt;WidgetOwnerId, which joins to WidgetOwner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a mermaid.js entity relationship diagram:&lt;/p&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
erDiagram
Widgets {
WidgetId int PK
WidgetTypeId int FK
WidgetOwnerId int FK
}
WidgetTypes {
WidgetTypeId int PK
WidgetTypeName varchar(255)
}
WidgetOwner {
WidgetOwnerId int PK
WidgetOwnerName varchar(255)
}
WidgetTypes ||--|{ Widgets : "Has"
WidgetOwner ||--|{ Widgets : "Has"
&lt;/div&gt;
&lt;/center&gt;
&lt;h2 id="what-wasnt-adding-up-ownerless-widgets"&gt;What Wasn&amp;rsquo;t Adding Up: Ownerless Widgets&lt;/h2&gt;
&lt;p&gt;Widgets was a very commonly used and core table for the OLTP database. What I found was that although the table had many millions of rows, all of them had a WidgetOwnerId&amp;hellip; except for around six rows. Only six.&lt;/p&gt;
&lt;p&gt;It smelled like a data cleansing problem at first, but when I had a look at the six rows I noticed something odd: they all had negative integers as the WidgetId, while every other row in the table had positive integer ids.&lt;/p&gt;
&lt;p&gt;In other words:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A handful of widgets had a negative WidgetId, and all of these rows had a null WidgetOwnerId&lt;/li&gt;
&lt;li&gt;Many millions of widgets each had a positive WidgetId, and all of these rows had a valid WidgetOwnerId&lt;/li&gt;
&lt;li&gt;All widgets had a WidgetTypeId.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This seemed like a clue. I began asking around about what the negative WidgetId values meant.&lt;/p&gt;
&lt;p&gt;The answer was that they were actually a very different type of widget altogether. But when that type of widget was implemented, a new WidgetType wasn&amp;rsquo;t created&amp;hellip; instead they re-used a different (let&amp;rsquo;s call it &amp;ldquo;incorrect&amp;rdquo;) WidgetType, and used a negative identifier to indicate that this wasn&amp;rsquo;t any ordinary widget.&lt;/p&gt;
&lt;p&gt;In other words, WidgetType was not only determined by the WidgetTypeId column in the table. To actually know the WidgetType, you also had to look at whether WidgetId was a positive or negative value.&lt;/p&gt;
&lt;h2 id="whats-so-terrible-about-this-let-us-count-the-ways"&gt;What&amp;rsquo;s So Terrible About This? Let Us Count the Ways&lt;/h2&gt;
&lt;p&gt;Essentially, we&amp;rsquo;ve got &amp;ldquo;hidden&amp;rdquo; business logic here, and it&amp;rsquo;s business logic which doesn&amp;rsquo;t follow the established conventions of normalization. Here&amp;rsquo;s the top three negative impacts:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad/breaking code.&lt;/strong&gt; This is a weird pattern that is not easy to notice. Anyone not intimately familiar with the data can easily make mistakes when working with this data, which could have significant impacts on applications using the OLTP database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra cognitive load.&lt;/strong&gt; This pattern is not easy to get comfortable with or to remember, especially if you&amp;rsquo;re not a data person. Having to teach everyone who works with this object the nuances of how it is designed, and have them remember how to work with it adds a weird complexity that is tough to remember.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Knock-on effects downstream.&lt;/strong&gt; Want to put this table in a data warehouse? The choices are to leave the structure as is, in which case you risk incorrect analytics / extra cognitive load for your analysts. Or you could build in complex transformations that may be very fragile depending on how the object changes in the future. Neither of these is a great option.&lt;/p&gt;
&lt;h2 id="the-root-cause-wasnt-dumb-people-it-was-a-cultural-problem"&gt;The Root Cause Wasn&amp;rsquo;t Dumb People&amp;hellip; It Was a Cultural Problem&lt;/h2&gt;
&lt;p&gt;To folks used to normalized data structures, this sounds pretty dumb. The tables were already normalized! Why make it weird?&lt;/p&gt;
&lt;p&gt;Well, this didn&amp;rsquo;t happen because folks didn&amp;rsquo;t understand normalization. This happened as a &amp;ldquo;creative&amp;rdquo; solution to ship some changes faster by reusing code. That decision was driven by strong pressure from a leader to meet deadlines.&lt;/p&gt;
&lt;p&gt;What became a technical problem was caused by a leader who created a problematic culture, in which folks felt like they didn&amp;rsquo;t have time to do the &lt;em&gt;right&lt;/em&gt; thing. Instead they live in a perpetual &amp;ldquo;just force it to work NOW&amp;rdquo; moment. It turns out the codebase was full of weird hacks that had been made to meet shipping demands and schedules. And the hacks were growing. This was merely one example.&lt;/p&gt;
&lt;p&gt;The result of a constant &amp;ldquo;just force it to work NOW&amp;rdquo; culture is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An extremely fragile production environment that breaks easily&amp;ndash; and even small errors cause full outages.&lt;/li&gt;
&lt;li&gt;An engineering team that has a hard time hiring junior or even mid-level software developers because of the cognitive load required to understand and work with the complex code.&lt;/li&gt;
&lt;li&gt;Frequent incorrect analytics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not an easy situation to dig out of while also building new features, so any changes need to be made carefully, bit by bit. And you also have to do something about all those fresh anti-patterns entering the architecture on the regular to get those new features shipped.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;a href="#ZgotmplZ"&gt;&lt;img src="https://kendralittle.com/images/tsql2sday-logo.jpg"
alt="The TSQL Tuesday logo" width="150"&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;h2 id="read-more-stories-of-code-that-made-folks-feel-a-certain-way"&gt;Read More Stories of Code That Made Folks Feel a Certain Way&lt;/h2&gt;
&lt;p&gt;This post was inspired by Erik Darling&amp;rsquo;s &lt;a href="https://erikdarlingdata.com/t-sql-tuesday-code-that-made-you-feel-a-way/"&gt;TSQL Tuesday topic, &amp;ldquo;Code That Made You Feel A Way&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check &lt;a href="https://erikdarlingdata.com/"&gt;Erik&amp;rsquo;s site&lt;/a&gt; for a follow up post to read more code feelings, and &lt;a href="http://tsqltuesday.com/"&gt;tsqltuesday.com&lt;/a&gt; for archives from past topics.&lt;/p&gt;</description></item><item><title>My Performance Tuning Precon and Git Session at PASS Data Community Summit 2023</title><link>https://kendralittle.com/2023/07/10/pass-data-community-summit-2023/</link><pubDate>Mon, 10 Jul 2023 10:11:37 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/07/10/pass-data-community-summit-2023/</guid><description>&lt;p&gt;I&amp;rsquo;m thrilled to be heading to Seattle in November for the &lt;a href="https://passdatacommunitysummit.com/"&gt;PASS Data Community Summit&lt;/a&gt;. My favorite things about the PASS Summit are making connections, learning from folks, broading my horizons, helping build a vibrant community, and teaching.&lt;/p&gt;
&lt;p&gt;Teaching is a great privilege, and I&amp;rsquo;m excited to be giving both a pre-conference session and a regular session. I chat about the sessions in this ~4 minute video.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/VoYDKpjSiRQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="my-precon---performance-tuning-secrets-learn-from-my-mistakes"&gt;My Precon - Performance Tuning Secrets: Learn From My Mistakes&lt;/h2&gt;
&lt;p&gt;I wanted to do something different for this day-long session, so I asked ChatGPT to generate an outline for a performance tuning session for SQL Server. The result was comprehensive, but it&amp;rsquo;s been done &lt;strong&gt;many&lt;/strong&gt; times before. It felt&amp;hellip; kinda boring. I&amp;rsquo;m flipping it upside down and building the session around my actual experiences, not from a list of concepts.&lt;/p&gt;
&lt;p&gt;During this day, we&amp;rsquo;ll:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delve into real-world stories and practical advice for tuning the SQL Server engine on-prem and in the cloud.&lt;/li&gt;
&lt;li&gt;Cover essential concepts like wait stats and query plans, along with an array of free tools.&lt;/li&gt;
&lt;li&gt;Approach these from a practical, real-world perspective, focusing on instances where I made mistakes or where alternative approaches might not have been apparent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From years of perf tuning and teaching it, both in the classroom and in consulting situations, I&amp;rsquo;ve found that an emphasis on practicality is critical: it&amp;rsquo;s what will help you keep from getting lost in the weeds over and over again.&lt;/p&gt;
&lt;p&gt;Database professionals need to adopt a strategic mindset, or we&amp;rsquo;ll end up constantly in reactive mode with a defensive mentality. While reactivity is important, we need to get ahead of potential issues and establish systems where risk is mitigated. Our goal is to create a safer and more stable environment, minimizing the need for constant reaction. While this is a straightforward concept, it&amp;rsquo;s very hard to understand what this means in reality without analyzing specific situations.&lt;/p&gt;
&lt;p&gt;Moving out of a reactive mindset doesn&amp;rsquo;t mean limiting or compromising what we do. We&amp;rsquo;ll explore how to properly performance-tune and build robust solutions. It&amp;rsquo;s a challenging task, but a fun one, and we&amp;rsquo;re going to tackle it in this session.&lt;/p&gt;
&lt;h2 id="my-regular-session-git-and-github-for-database-folks"&gt;My Regular Session: Git and GitHub for Database Folks&lt;/h2&gt;
&lt;p&gt;Version control is essential for automation and has become a fundamental skill in software development and IT. I use Git on a regular basis and, weirdly enough, I even find it fun.&lt;/p&gt;
&lt;p&gt;In this session, we&amp;rsquo;ll cover the basics and build up the necessary skills. The good news is that learning these skills has never been easier. There are numerous helpful free and paid tools available to make using git more enjoyable and accessible than ever before.&lt;/p&gt;
&lt;h2 id="i-drew-a-comic"&gt;I Drew a Comic&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/kendra-little-sessions-pass-data-community-summit-2023-comic.png"
alt="A six panel comic. Panel 1: a question from outside the frame asking a corgi, &amp;#39;what sessions are you giving?&amp;#39;. Panel 2: The corgi at a microphone with the message that I&amp;#39;m giving a precon, Perf Tuning Secrets, Learn from my mistakes. Panel 3: two corgis running with an explosion labeled &amp;#39;real world approach, practical advice&amp;#39;. Panel 4: a corgi who may be driving in a spaceship with the label, &amp;#39;escape the 2005 IT orbit: the protector with a reactive mindset&amp;#39;. Panel 5: a corgi with a futuristic robot body saying that the regular session is on Git, and it&amp;#39;s practical, fun, easier than ever. Panel 6: a dorky smiling corgi with the message &amp;#39;hope to see you there&amp;#39;." width="700"&gt;
&lt;/figure&gt;
&lt;h2 id="how-to-register"&gt;How to Register&lt;/h2&gt;
&lt;p&gt;Check out more about the conference and register at the &lt;a href="https://passdatacommunitysummit.com/"&gt;PASS Data Community Summit site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope to see you in Seattle in November!&lt;/p&gt;</description></item><item><title>Adding a Netlify Contact Form to a Hugo Static Site</title><link>https://kendralittle.com/2023/06/29/adding-netlify-contact-form-hugo-mainroad/</link><pubDate>Thu, 29 Jun 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/06/29/adding-netlify-contact-form-hugo-mainroad/</guid><description>&lt;p&gt;I redid my static site&amp;rsquo;s contact form with a free option from my host, Netlify.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s why I changed my static site host and how I got a Netlify contact form to work with a blog built on Hugo and the Mainroad theme.&lt;/p&gt;
&lt;h2 id="why-i-moved-to-netlify"&gt;Why I Moved to Netlify&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/netlify-contact-form.png" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;I wrote back in 2021 about &lt;a href="https://kendralittle.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/"&gt;Moving From WordPress to an Azure static site with Hugo&lt;/a&gt;. Since then, I migrated away from Azure Static Sites to &lt;a href="https://www.netlify.com/pricing/"&gt;Netlify&amp;rsquo;s free plan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I moved to Netlify for a couple of reasons:&lt;/p&gt;
&lt;h3 id="1-i-was-hitting-storage-quotas-with-the-azure-static-site-that-caused-deployments-to-fail"&gt;1. I was hitting storage quotas with the Azure static site that caused deployments to fail&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;d already reduced image file sizes where it made sense and moved larger files off to 3rd party services for hosting and embedding. There was little advice on troubleshooting this issue in Azure, and I have a lot of hobbies to tend to.&lt;/p&gt;
&lt;p&gt;Netlify&amp;rsquo;s free plan doesn&amp;rsquo;t have this limitation.&lt;/p&gt;
&lt;h3 id="2-netlify-offers-some-other-cool-things-on-the-free-plan-such-as-the-ability-to-use-interactive-forms-hosted-on-their-servers"&gt;2. Netlify offers some other cool things on the free plan, such as the ability to use interactive forms hosted on their servers&lt;/h3&gt;
&lt;p&gt;While I&amp;rsquo;d previously set up a simple option embedding a Google form on my contact page, I didn&amp;rsquo;t love the workflow with this solution. I wanted something better.&lt;/p&gt;
&lt;p&gt;I probably should have blogged about how I migrated to Netlify, if only because it was so simple that I barely remember what I did. I remember that Netlify walked me through everything, and that it was quite easy. I don&amp;rsquo;t think I even had to provide a credit card number in the process.&lt;/p&gt;
&lt;p&gt;It took me a while to get around to redoing my contact form, and here&amp;rsquo;s how I did it.&lt;/p&gt;
&lt;h2 id="enable-form-detection-in-netlify"&gt;Enable Form Detection in Netlify&lt;/h2&gt;
&lt;p&gt;First, you&amp;rsquo;ll need to enable forms in your Netlify site configuration.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sign into the Netlify UI, then go to &lt;code&gt;Site configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;Forms&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Enable form detection&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This won&amp;rsquo;t do anything right away. The next time you deploy the site, Netlify will look for forms which want to hook up.&lt;/p&gt;
&lt;h2 id="start-serving-your-site-locally"&gt;Start Serving Your Site Locally&lt;/h2&gt;
&lt;p&gt;From a terminal, I ran: &lt;code&gt;hugo serve&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I then regularly referred to my locally served version of the site as I stepped through the following. This helped me check functionality as I saved changes to ensure I knew what was working.&lt;/p&gt;
&lt;h2 id="create-a-hugo-html-layout-for-your-contact-page-form"&gt;Create a Hugo HTML Layout for Your Contact Page Form&lt;/h2&gt;
&lt;p&gt;While there are several posts and tutorials out there on how to do this, I hadn&amp;rsquo;t worked with Hugo in a minute. I had to spend some time remembering how this all works, and which files I even use for html. Oh, right, the magic happens in Go templates!&lt;/p&gt;
&lt;p&gt;Under my &lt;code&gt;layouts&lt;/code&gt; folder, I added a new folder, &lt;code&gt;contact&lt;/code&gt;. In this folder I created a new file named &lt;code&gt;single.html&lt;/code&gt;.&lt;/p&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
graph LR
C["📁 content"] --&gt; layouts["📁 layouts"] --&gt; single-html["single.html"]
&lt;/div&gt;
&lt;/center&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{ define &amp;#34;main&amp;#34; }}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;main&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form width-normal&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/contact-thank-you/&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;data-netlify&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;netlify-honeypot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bot-field&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;form-name&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;bot-field&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;&amp;lt;!-- Text input--&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1 control-label&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-name&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;form-control input-md&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;autocomplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;off&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;maxlength&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;100&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;&amp;lt;!-- Text input--&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1 control-label&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-email&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Email&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;email&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Email&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;form-control input-md&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;autocomplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;off&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;maxlength&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;100&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;&amp;lt;!-- Text input--&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1 control-label&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Subject&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-subject&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Subject&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Subject&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;form-control input-md&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;autocomplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;off&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;maxlength&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;&amp;lt;!-- Textarea --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-1 control-label&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;form-control&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-form-message&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;What&amp;#39;s up?&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;8&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;&amp;lt;!-- Button --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;contact-button&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;submit&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Submit&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Form-submit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{ partial &amp;#34;authorbox.html&amp;#34; . }}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{ partial &amp;#34;pager.html&amp;#34; . }}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{ end }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="some-notes-on-this-form"&gt;Some Notes on this Form&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The form opening tag specifies &lt;code&gt;data-netlify=&amp;quot;true&amp;quot;&lt;/code&gt;. This means that the next time you publish the site, the form may be detected by Netlify, as long as you&amp;rsquo;ve enabled forms on the site.&lt;/li&gt;
&lt;li&gt;The form opening tag specifies &lt;code&gt;netlify-honeypot=&amp;quot;bot-field&amp;quot;&lt;/code&gt;. There is also an input named bot-field that has a css class specified named hidden. Together, these are used as a &lt;a href="https://docs.netlify.com/forms/spam-filters/#honeypot-field"&gt;spam reduction feature in Netlify&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, as long as you don&amp;rsquo;t already have a &lt;code&gt;contact&lt;/code&gt; folder which this template would apply to, you shouldn&amp;rsquo;t notice any differences in your locally served copy of your site.&lt;/p&gt;
&lt;h2 id="create-a-contact-page-that-references-the-layout"&gt;Create a Contact Page That References the Layout&lt;/h2&gt;
&lt;p&gt;If I was adding a new contact page, I could have added a new folder named &lt;code&gt;content/contact&lt;/code&gt;. This would automatically pick up the contact template.&lt;/p&gt;
&lt;p&gt;However, I already had a contact page in place with a URL I wanted to maintain that didn&amp;rsquo;t involve a &amp;ldquo;contact&amp;rdquo; subfolder, so I edited my existing file which I had under &lt;code&gt;content/contact-kendra-little.md&lt;/code&gt;.&lt;/p&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
graph LR
C["📁 content"] --&gt; contact["📁 contact"] --&gt; contactkendra["contact-kendra-little.md"]
&lt;/div&gt;
&lt;/center&gt;
&lt;p&gt;The entire definition of this page is as follows. The important bit is that I added the line &lt;code&gt;type: contact&lt;/code&gt; to the front matter so that it will pick up that layout.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Contact&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;authorbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;pager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, your locally served copy of the site should have a contact form which displays the html form in the template.&lt;/p&gt;
&lt;p&gt;The styling, however, may look a little wonky. Mine sure did. And if you don&amp;rsquo;t have any css already that hides fields with a class named &lt;code&gt;hidden&lt;/code&gt;, you will also see the honeypot field on your form, which will look odd.&lt;/p&gt;
&lt;h2 id="add-css-styling-as-needed"&gt;Add CSS Styling as Needed&lt;/h2&gt;
&lt;p&gt;The next thing I had to remember was where to customize css files. At this point, I asked GitHub Copilot for help:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/asking-copilot-help-css.png"
alt="Screenshot showing GitHub Copilot being asked for help with CSS code" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;I already had a file named &lt;code&gt;static/css/custom.css&lt;/code&gt;, but create one if needed.&lt;/p&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
graph LR
C["📁 content"] --&gt; static["📁 static"] --&gt; css["📁 css"] --&gt; custom-css["custom.css"]
&lt;/div&gt;
&lt;/center&gt;
&lt;p&gt;I added the following css to get my form working, using my locally served copy of the site as I made changes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;hidden&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;contact-form-1&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;contact-form-1&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Lucida Sans&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Lucida Sans Regular&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Lucida Grande&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Lucida Sans Unicode&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Geneva&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Verdana&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;/* Add a background color and padding */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;contact-form-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;/* Style the submit button */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;contact-button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#ff8400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;contact-button&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#ff5100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="create-a-thank-you-page-optional"&gt;Create a Thank-You Page (Optional)&lt;/h2&gt;
&lt;p&gt;My form declaration specifies &lt;code&gt;action=&amp;quot;/contact-thank-you/&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
let isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let mermaidTheme = (isDark) ? 'dark' : 'default';
let mermaidConfig = {
theme: mermaidTheme,
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(mermaidConfig);
&lt;/script&gt;
&lt;center&gt;
&lt;div class="mermaid"&gt;
graph LR
C["📁 content"] --&gt; custom-css["contact-thank-you.md"]
&lt;/div&gt;
&lt;/center&gt;
&lt;p&gt;I created a page at &lt;code&gt;content/contact-thank-you.md&lt;/code&gt; with the following definition:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Thanks for getting in touch&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;authorbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;pager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;most&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;within&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;few&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;business&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{{&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;figure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/images/contact-kendra-little.jpg&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;650&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="commit-your-changes-and-deploy-the-site"&gt;Commit Your Changes and Deploy the Site&lt;/h2&gt;
&lt;p&gt;To actually test the form, you need to commit your changes and deploy your site. You can do this a bunch of ways with Netlify&amp;ndash; go with whatever you are comfortable with, and which meets the requirements of your site.&lt;/p&gt;
&lt;h2 id="configure-email-notifications-for-form-submissions"&gt;Configure Email Notifications for Form Submissions&lt;/h2&gt;
&lt;p&gt;I want to get an email when someone fills out the contact form on my site. You can configure this in the Netlify UI by &lt;a href="https://docs.netlify.com/forms/notifications/"&gt;enabling email notifications for one or more forms&lt;/a&gt;. Essentially:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log into Netlify.&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;Site configuration&lt;/code&gt; -&amp;gt; &lt;code&gt;Forms&lt;/code&gt; -&amp;gt; &lt;code&gt;Form notifications&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Add notification&lt;/code&gt;, then step through the wizard to configure the notification.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="test-and-troubleshoot"&gt;Test and Troubleshoot&lt;/h2&gt;
&lt;p&gt;Now test out using the form on your published site, and make sure you get the email.&lt;/p&gt;
&lt;p&gt;Netlify provides &lt;a href="https://docs.netlify.com/forms/troubleshooting-tips/"&gt;troubleshooting tips&lt;/a&gt; if you run into problems.&lt;/p&gt;
&lt;h2 id="related-links"&gt;Related Links&lt;/h2&gt;
&lt;p&gt;I used the following sources as references when setting this up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.netlify.com/forms"&gt;Netlify docs on forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://answers.netlify.com/t/support-guide-creating-netlify-forms-in-hugo/84261"&gt;Netlify support guide on Creating Netlify Forms in Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://brianli.com/how-to-create-a-contact-form-in-hugo-with-netlify-forms/"&gt;How to Create a Contact Form in Hugo with Netlify Forms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Is It OK to Show My Database Schema to ChatGPT and GitHub Copilot?</title><link>https://kendralittle.com/2023/06/23/chat-gpt-copilot-data-privacy-questions/</link><pubDate>Fri, 23 Jun 2023 10:12:56 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/06/23/chat-gpt-copilot-data-privacy-questions/</guid><description>&lt;p&gt;&lt;em&gt;I&amp;rsquo;m answering two questions from Brent Ozar&amp;rsquo;s list of &lt;a href="https://www.brentozar.com/archive/2023/06/its-friday-im-not-answering-these-office-hours-questions"&gt;user questions open for answers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Q: What’s your opinion of entering confidential info in chat gpt? Will we see AI therapist chat bots?&lt;/p&gt;
&lt;p&gt;Q: In terms of security, is it OK to expose your database to tools like GitHub Copilot in Azure Data Studio? Someone will know that your email address column is not encrypted or a stored procedure is not parsing its input parameters when dynamic T-SQL is built.&lt;/p&gt;
&lt;h2 id="always-check-the-data-privacy-policy-and-related-docs-for-each-tool-and-chat-with-your-management"&gt;Always Check the Data Privacy Policy and Related Docs for Each Tool, and Chat With Your Management&lt;/h2&gt;
&lt;p&gt;In general, it&amp;rsquo;s best to assume that any data you enter into an online website or into an extension or tool may be stored, used, shared, or sold&amp;ndash; until you find documentation that explicitly promises otherwise. This is true both for generative AI tools as well as any other tooling.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also best to chat with your leadership about this. Many companies have very specific policies about what you can and cannot do with company data.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/bear-asks-your-data-questions-chat-gpt.png"
alt="A bear character asking questions about data privacy with ChatGPT, illustrating concerns about sharing database information" width="700"&gt;
&lt;/figure&gt;
&lt;h2 id="chatgpt-and-openai"&gt;ChatGPT and OpenAI&lt;/h2&gt;
&lt;p&gt;Don’t enter someone else’s confidential info into the ChatGPT website. Don’t enter your own confidential info into the ChatGPT website unless you want it to no longer be confidential. The &lt;a href="https://openai.com/policies/privacy-policy"&gt;privacy policy&lt;/a&gt; and related article, &lt;a href="https://help.openai.com/en/articles/7842364-how-chatgpt-and-our-language-models-are-developed"&gt;How ChatGPT and Our Language Models Are Developed&lt;/a&gt; go into more information about how data shared with ChatGPT&amp;rsquo;s website is used.&lt;/p&gt;
&lt;p&gt;Note that the ChatGPT website is &lt;strong&gt;not&lt;/strong&gt; the same as the &lt;a href="https://azure.microsoft.com/en-us/products/cognitive-services/openai-service"&gt;Azure Open AI service&lt;/a&gt;. These are different tools, and they have different privacy policies. For the Azure Open AI Service, the article &lt;a href="https://learn.microsoft.com/en-us/legal/cognitive-services/openai/data-privacy"&gt;Data, privacy, and security for Azure OpenAI service&lt;/a&gt; covers what data is processed and how it is used.&lt;/p&gt;
&lt;p&gt;It is possible to use the Open AI service under a data agreement that opts you out of the logging and human review process, but you need to specifically arrange that. In other words, it is possible for applications to be built that can use even very sensitive, highly confidential, or tightly regulated data safely with these services.&lt;/p&gt;
&lt;h2 id="github-copilot"&gt;GitHub Copilot&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re using GitHub Copilot for business, check out the &lt;a href="https://docs.github.com/en/site-policy/privacy-policies/github-copilot-for-business-privacy-statement"&gt;GitHub Copilot for Business Privacy Statement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The statement explains that snippets of your code that are used to provide suggestions are discarded after suggestions are returned, and are not retained. It does collect some telemetry data regarding how you use the IDE and editor along with general usage data.&lt;/p&gt;
&lt;p&gt;GitHub Copilot has now been around long enough that many software development companies have reviewed the product and created a policy about whether or not it should be used by the organization, so checking with your management can save you some time especially in this case.&lt;/p&gt;
&lt;h2 id="what-about-all-these-other-copilots"&gt;What About All These Other &amp;ldquo;Copilots&amp;rdquo;?&lt;/h2&gt;
&lt;p&gt;Lots of companies, including Microsoft, are introducing assistants and copilots throughout their platforms.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sorry, but we&amp;rsquo;re gonna get to check the data privacy statements for each one, friends. Here&amp;rsquo;s &lt;a href="https://learn.microsoft.com/en-us/power-platform/transparency-note-copilot-data-security-privacy"&gt;an example for the Microsoft Power Platform&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="ai-therapists-have-been-around-for-a-while"&gt;AI Therapists Have Been Around for a While&lt;/h2&gt;
&lt;p&gt;AI Therapist chatbots already exist, and have for a while, actually!&lt;/p&gt;
&lt;p&gt;One I like is “Woebot” – &lt;a href="https://woebothealth.com/"&gt;https://woebothealth.com/&lt;/a&gt;. Woebot is a free app (at least for now, has been for a while though) that specializes in cognitive behavioral therapy style conversations.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://woebothealth.com/faq/"&gt;Woebot FAQ&lt;/a&gt; talks a bit about how the data is stored and options to delete it, and the &lt;a href="https://woebothealth.com/privacy-webview/"&gt;privacy policy&lt;/a&gt; specifies under what conditions they will share data with third parties.&lt;/p&gt;</description></item><item><title>When NOT to Choose SQL Server to Store Your Data</title><link>https://kendralittle.com/2023/06/21/when-not-to-choose-sql-server/</link><pubDate>Wed, 21 Jun 2023 12:29:57 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/06/21/when-not-to-choose-sql-server/</guid><description>&lt;p&gt;I recently posted on LinkedIn that I was interviewing for a SQL Server database administrator role for the first time in a long time. I invited folks: &amp;ldquo;Ask me your favorite interview question!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephen-vakil-0635a711/"&gt;Stephen Vakil&lt;/a&gt; had a great one: &amp;ldquo;when should you use SQL Server to store your data?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;For situations where SQL Server is already in use and there&amp;rsquo;s a relatively low barrier to entry, I think it&amp;rsquo;s simpler to turn this question around and ask, &amp;ldquo;When is SQL Server &lt;em&gt;not&lt;/em&gt; a good choice for storing your data?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is also available as &lt;a href="https://dearsqldba.libsyn.com/site/when-not-to-choose-sql-server-to-store-your-data"&gt;a podcast episode&lt;/a&gt;, and &lt;a href="https://www.youtube.com/live/8o6efUFkNCw"&gt;on YouTube&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="you-dont-actually-need-a-database"&gt;You Don&amp;rsquo;t Actually Need a Database&lt;/h2&gt;
&lt;p&gt;This is going to seem like an obvious question but&amp;hellip;. do you actually need a database?&lt;/p&gt;
&lt;p&gt;Would flat files work for your purpose? Do you only need a readable cache and very low latency? Would an API interface be better? (And maybe what&amp;rsquo;s behind it is a database, or maybe it&amp;rsquo;s not.)&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s very easy to get comfortable with a database that the team is quite familiar with, and to default to using it. Especially because of this, it&amp;rsquo;s a good practice to as regularly: do we need this in a database? Is there a less expensive and easier to manage option, or an architecture that would work better in the long run?&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/comic-how-databases-are-born.png"
alt="A comic illustration showing how databases are created, questioning whether a database is actually needed"&gt;
&lt;/figure&gt;
&lt;h2 id="youre-not-using-structured-data"&gt;You&amp;rsquo;re Not Using Structured Data&lt;/h2&gt;
&lt;p&gt;SQL Server&amp;rsquo;s primary strength is being a reliable, high performing relational database that handles structured data well. This means it&amp;rsquo;s great for situations where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have or can develop a schema with fixed columns that have suitable data types. (Aka &amp;ldquo;structured data&amp;rdquo;.)&lt;/li&gt;
&lt;li&gt;You want to apply some level of &lt;a href="https://en.wikipedia.org/wiki/Database_normalization"&gt;normalization&lt;/a&gt; to the data to reduce duplication and enforce integrity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the core scenario where the SQL Server database engine and query optimization shine.&lt;/p&gt;
&lt;p&gt;While SQL Server &lt;strong&gt;can&lt;/strong&gt; deal with unstructured data, if this is the primary use case for the application then a type of database that is designed to optimize storing and accessing unstructured data is worth considering. Databases that specialize in handling unstructured data include MongoDB and Couchbase, but the right choice will vary by your use case, your deployment scenario (cloud/on-prem), and other variables considered below.&lt;/p&gt;
&lt;p&gt;If you are not interested in normalizing data in SQL Server because you wish to use the database primarily for analytics, you might also want to consider other databases&amp;hellip;&lt;/p&gt;
&lt;h2 id="you-dont-have-an-oltp-or-mixed-workload---you-want-only-analytics-for-example"&gt;You Don&amp;rsquo;t Have an OLTP or Mixed Workload - You Want Only Analytics, for Example&lt;/h2&gt;
&lt;p&gt;SQL Server is very good at transactional processing, with lots of inserts, updates, and deletes. SQL Server has multiple options on how to implement ACID compliant transactions when you have a workload that consists of concurrent reads and writes. Here&amp;rsquo;s a review of those ACID properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Atomic&lt;/strong&gt; - transactions are &amp;ldquo;all or nothing,&amp;rdquo; meaning they complete in their entirety or roll back in their entirety.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent&lt;/strong&gt; - transactions must follow all implemented database constraints or business logic implemented by structures in the database. For example, if a transaction violates a unique constraint, it must fail and roll back in its entirety.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolated&lt;/strong&gt; - transactions shouldn&amp;rsquo;t interfere with one another if running simultaneously &amp;ndash; or at least, they should only interfere with one another based on what you have set as your isolation level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable&lt;/strong&gt; - transactions can&amp;rsquo;t vanish after they commit, even if there is a power or system failure. This means that the transaction information must be stored in a non-volatile way (think writing to disk). Write-ahead logging (WAL) helps achieve this in SQL Server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your primary use case for SQL Server is an OLTP workload, but you&amp;rsquo;d also like to do some reporting against those tables, that can sometimes work well in SQL Server: it even has a columnar storage option that can help with large scans.&lt;/p&gt;
&lt;p&gt;However, if your primary or only use case for a database is reporting or analytics, you might not want to use &amp;ldquo;classic&amp;rdquo; SQL Server. Depending on your use case, you might consider a database or warehousing approach designed purely for analytics. There are many different options for analytics workloads, but here are three that come up a lot these days:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lakehouse approaches&lt;/strong&gt;, which combine data lake and data warehouse components, are increasingly popular, especially when you have large amounts of raw data. Databricks is a leading vendor in this space.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Columnar databases&lt;/strong&gt;, such as Snowflake, have been developed specifically to optimize analytics workloads within a PAAS offering. When there is a desire to have SQL &amp;ldquo;just go fast&amp;rdquo; with minimal administration for structured data, these specialized databases shine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vector databases&lt;/strong&gt; enable very fast search and retrieval of data based on its similarity or relevance to other data. These are very popular for analytics related to Natural Language Processing (NLP).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="you-need-to-write-to-multiple-nodes-for-a-single-database"&gt;You Need to Write to Multiple Nodes for a Single Database&lt;/h2&gt;
&lt;p&gt;Technically, SQL Server has an option for having multiple writeable copies of a database: peer-to-peer replication.&lt;/p&gt;
&lt;p&gt;But I haven&amp;rsquo;t heard of anyone deploying a new peer-to-peer setup in many years. It&amp;rsquo;s not a popular choice, because it tends to be pretty fragile: you need to design the schema carefully to avoid having a lot of conflicts if the same rows are updated on different nodes. Microsoft &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/replication/transactional/peer-to-peer-transactional-replication"&gt;recommends&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To avoid potential data inconsistency, make sure that you avoid conflicts in a peer-to-peer topology, even with conflict detection enabled. To ensure that write operations for a particular row are performed at only one node, applications that access and change data must partition insert, update, and delete operations. This partitioning ensures that modifications to a given row originating at one node are synchronized with all other nodes in the topology before the row is modified by a different node.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Essentially, some very specific application designs may work with peer to peer replication, but even then, living with P2P and troubleshooting it in real-world scenarios is quite complex and time consuming. I would generally look at other options first if I need to scale out writes for a single database.&lt;/p&gt;
&lt;p&gt;Other options for SQL Server, including Azure SQL variations of SQL Server, allow only one writable node for a database.&lt;/p&gt;
&lt;h2 id="your-team-wants-a-paas-solution"&gt;Your Team Wants a PaaS Solution&lt;/h2&gt;
&lt;p&gt;This is just a terminology thing&amp;ndash; &amp;ldquo;SQL Server&amp;rdquo; generally refers to the &amp;ldquo;boxed software&amp;rdquo; version of SQL Server that you either install yourself, or run pre-installed on a VM in an implementation like SQL Server on Azure VM.&lt;/p&gt;
&lt;p&gt;SQL Server can require quite a lot of care and feeding: backups, maintenance, configuration, upgrades/patching, and monitoring. By using a Platform as a Service (PaaS) option, you can limit &lt;em&gt;some&lt;/em&gt; of this work.&lt;/p&gt;
&lt;p&gt;For these cases, a hosted database option can be the right answer. This might be something very similar to SQL Server, like Azure SQL Database, Azure SQL Managed Instance, or Amazon RDS for SQL Server. Or a hosted version of another relational database, based on your preference, might fit, depending on the requirements of the situation .&lt;/p&gt;
&lt;h2 id="your-team-needs-a-cheap-solution"&gt;Your Team Needs a Cheap Solution&lt;/h2&gt;
&lt;p&gt;SQL Server licensing gets expensive quickly. Sometimes this leads to people just throwing things on the SQL Server: hey, we paid a lot for these licenses, might as well use it!&lt;/p&gt;
&lt;p&gt;And while that&amp;rsquo;s fine in many cases, eventually adding on all those use cases will likely lead to spending &lt;em&gt;more&lt;/em&gt; on SQL Server licensing. Cost is generally a consideration for any project, and if you need a cheap solution then SQL Server generally shouldn&amp;rsquo;t be your first choice. (Unless, of course, you work at a place that uses a lot of Oracle. In that case, the SQL Server will look cheap.)&lt;/p&gt;</description></item><item><title>Career Navigation in the Time of Tech Layoffs</title><link>https://kendralittle.com/2023/05/23/career-planning-styles-in-times-layoffs/</link><pubDate>Tue, 23 May 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/05/23/career-planning-styles-in-times-layoffs/</guid><description>&lt;p&gt;Reorganizations and layoffs are now commonplace in the tech industry: a daily occurrence. It&amp;rsquo;s increasingly necessary for tech workers mentally prepare for potential job loss and uncertainties that arise. It&amp;rsquo;s a common antipattern to believe that it&amp;rsquo;s &amp;ldquo;too late&amp;rdquo; to prepare for a layoff or unexpected reorganization if a layoff has already occurred in your organization.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s never too late, and it&amp;rsquo;s always the right time these days to start mentally preparing yourself for change&amp;ndash; because there&amp;rsquo;s reliably another change around the corner.&lt;/p&gt;
&lt;h2 id="the-reality-of-tech-layoffs"&gt;The Reality of Tech Layoffs&lt;/h2&gt;
&lt;p&gt;Even tech companies raking in millions or billions in profits for shareholders are cutting costs, laying off workers, and talking about reductions in force. The phrases &amp;ldquo;economic headwinds&amp;rdquo; and &amp;ldquo;I take full responsibility&amp;rdquo; are both doing a massive amount of work, and these repeated excuses contribute to an environment of uncertainty. The hype cycle over AI and rapid changes in technical capabilities also contribute to erratic executive decisions and tech worker worries. Acknowledging the stress and challenges that come with these situations is helpful for preparing ourselves mentally.&lt;/p&gt;
&lt;p&gt;Navigating through layoffs, reorganizations, and technical evolutionary moments requires a resilient mindset. It&amp;rsquo;s important to acknowledge the potential impact on our careers and emotions. Uncertainty can breed anxiety and fear, but being mentally prepared helps us approach the situation with a sense of control and adaptability.&lt;/p&gt;
&lt;p&gt;I remind myself often that change is inevitable, and that sometimes changes that start with a lot of discomfort lead to opportunities. I encourage myself to focus on building my powers of resilience, which I think of as a type of mental &amp;lsquo;muscle&amp;rsquo;.&lt;/p&gt;
&lt;h2 id="lots-of-us-dont-have-a-detailed-plan-for-what-to-do-next"&gt;Lots of Us Don&amp;rsquo;t Have a Detailed Plan for What to Do Next&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/linkedin-poll-layoffs.png"
alt="Screenshot of a LinkedIn poll showing how people are approaching career planning during tech layoffs" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;I recently ran a poll among my LinkedIn network and asked how folks are approaching this time. With 194 respondents, the results included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;24% of respondents are &amp;ldquo;hoping for the best,&amp;rdquo; indicating that they may not have a specific career direction in mind but are optimistic about finding opportunities.&lt;/li&gt;
&lt;li&gt;37% of respondents have a general direction they know they want to go in but haven&amp;rsquo;t yet developed a detailed plan. This group recognizes the need for change but requires further clarity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;More than 50% of us don&amp;rsquo;t have a basic or detailed plan for what to do if our job is suddenly eliminated.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think that everyone needs a detailed plan. I do think that there are some steps that we all can take that will make our lives easier, however, especially if we aren&amp;rsquo;t in a situation where we are ready to form a detailed plan.&lt;/p&gt;
&lt;p&gt;I personally am in the &amp;ldquo;general direction&amp;rdquo; bucket, because I think I don&amp;rsquo;t want my next job to have the same job title as I have now &amp;ndash; I think for my next job I probably want to do something a bit different from Technical Product Management. I&amp;rsquo;m not 100% what that looks like, but I will benefit from doing what I can to explore my future interests now, even if at a high level.&lt;/p&gt;
&lt;h2 id="revive-or-build-your-network"&gt;Revive or Build Your Network&lt;/h2&gt;
&lt;p&gt;For many of us, building connections and reviving our professional network helps orient us mentally and can be a first step to improving mental resilience: it helps us feel less isolated.&lt;/p&gt;
&lt;p&gt;Consider reconnecting with and seeking support from trusted colleagues, mentors, and your professional networks. Connecting with others who are experiencing similar situations can provide valuable insights and emotional support, helping you navigate through the uncertainty with greater confidence.&lt;/p&gt;
&lt;p&gt;If, like me, you are considering of shifting your career direction, this can be a great time to set up informational interviews (which can be done synchronously or through chat or email) with people you respect to ask about roles which you find interesting. You can ask for advice: what makes people excellent in this role? What are the table stakes for getting into this type of role? What would the person advise someone with your background and skills to do to move into that type of role in the future?&lt;/p&gt;
&lt;p&gt;These conversations can not only help inform you and give you a greater sense of direction, but they also build your network and can revive past connections that have faded.&lt;/p&gt;
&lt;h2 id="consider-a-flexible-career-plan"&gt;Consider a Flexible Career Plan&lt;/h2&gt;
&lt;p&gt;Having a general career direction can provide a sense of stability. A flexible career plan allows you to adapt a bit where you are, and can also offer benefits for your current employer.&lt;/p&gt;
&lt;p&gt;In a time of rapid change, layoffs, and reorgs, there are often ways to seek opportunities within your current job to develop skills that align with your desired future role. The trick here is that your manager is generally not going to do this for you: this is usually something you need to think of and pitch for yourself. You may need to try multiple times to suggest changes in how you work for it to stick, as well.&lt;/p&gt;
&lt;p&gt;Think about areas where you want to grow and how you can leverage available resources, such as training programs or cross-functional projects. Perhaps brainstorm with a colleague how you can do things in a different way that is a benefit to your team and company as well as yourself.&lt;/p&gt;
&lt;h2 id="avoid-the-trap-of-overworking"&gt;Avoid the Trap of Overworking&lt;/h2&gt;
&lt;p&gt;A common antipattern that folks fall into in a time of &amp;ldquo;economic headwinds&amp;rdquo; is believing that working excessive hours is the ultimate shield against layoffs. Not only is this untrue in my experience, it&amp;rsquo;s also bad for your mental resilience.&lt;/p&gt;
&lt;p&gt;Workforce reductions often do NOT spare those who work the hardest or the longest hours, for various reasons. Overworking increases your risk of burnout and takes a toll on your health. Focusing on limiting your time working and in building mental resilience and your network will help you more in the long run.&lt;/p&gt;</description></item><item><title>ChatGPT Says SSMS Is the Best SQL Server Monitoring Tool</title><link>https://kendralittle.com/2023/05/03/ssms-is-the-best-sql-server-monitoring-tool-chatgpt/</link><pubDate>Wed, 03 May 2023 08:27:18 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/05/03/ssms-is-the-best-sql-server-monitoring-tool-chatgpt/</guid><description>&lt;p&gt;One thing I enjoy about AI chatbots is that they can help me recognize when I&amp;rsquo;ve missed something obvious.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Bot-250.png"
alt="A robot or bot character illustration representing ChatGPT"&gt;
&lt;/figure&gt;
&lt;h2 id="the-question"&gt;The Question&lt;/h2&gt;
&lt;p&gt;I prompted ChatGPT (free version) with: &amp;ldquo;What are the top 10 products to monitor sql server databases? List the top three features and drawbacks of each, give detailed contrasts/comparisons of the top 3 by popularity.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;It responded with a list, and the top winner of this popularity contest was: SQL Server Management Studio (SSMS).&lt;/p&gt;
&lt;h2 id="my-initial-reaction"&gt;My Initial Reaction&lt;/h2&gt;
&lt;p&gt;My first thought was, &amp;ldquo;that&amp;rsquo;s not a monitoring tool!&amp;rdquo;&lt;/p&gt;
&lt;h2 id="what-the-robot-said"&gt;What the Robot Said&lt;/h2&gt;
&lt;p&gt;But I was thinking about SSMS and my question incorrectly. ChatGPT pointed out that SSMS&amp;rsquo; top features are that it&amp;rsquo;s free, included with SQL Server, has an extensive toolset, and is easy to use. The drawbacks are that it has limited automation, lacks real-time monitoring, can be slow on large databases. At the end of the list of tools, ChatGPT suggested that, &amp;ldquo;the best SQL server monitoring tool for your organization will depend on the size and complexity of your databases, your budget, and your custom monitoring requirements.&amp;rdquo; And that&amp;rsquo;s absolutely true.&lt;/p&gt;
&lt;h2 id="what-i-learned"&gt;What I Learned&lt;/h2&gt;
&lt;p&gt;This uncovered an assumption I hadn&amp;rsquo;t realized that I hold: when I use the term &amp;ldquo;monitoring,&amp;rdquo; I assume that monitoring is automated. This is only a subset of monitoring, however. In many environments, it may be acceptable for monitoring to be manual, depending on the factors listed above. And when there&amp;rsquo;s no budget and very limited monitoring requirements, SSMS is a fine choice!&lt;/p&gt;
&lt;p&gt;As we enter the world of the Rising Chatbots, I use these tools more and more. I don&amp;rsquo;t trust that the tools output accurate information, but rather that they might lead me in the direction of useful information or output, as long as I put in the due diligence needed to use it wisely.&lt;/p&gt;</description></item><item><title>Use ChatGPT to See Multiple Perspectives: An Example With ORMs and Database Code</title><link>https://kendralittle.com/2023/01/24/chat-gpt-discusses-orms-and-databases/</link><pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/01/24/chat-gpt-discusses-orms-and-databases/</guid><description>&lt;p&gt;There&amp;rsquo;s a lot of hype, concern, and fear regarding generative AI lately. Tools like ChatGPT are so good at generating groups of words that it feels like magic&amp;ndash; however, generative AI doesn&amp;rsquo;t have the ability to understand or verify the language it generates. For example, it&amp;rsquo;s been &lt;a href="https://www.theverge.com/2023/1/20/23564311/cnet-pausing-ai-articles-bot-red-ventures"&gt;used to write news stories for CNET&lt;/a&gt; &amp;ndash; but sometimes included facts that are &lt;a href="https://futurism.com/cnet-ai-errors"&gt;just plain wrong&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One positive use case of a generative AI tool like ChatGPT is to ask it to make a case for different perspectives than your own, and use this as a starting point to broaden your understanding &amp;ndash; with the knowledge that we need to verify everything ChatGPT tells us. As an example, let&amp;rsquo;s chat to ChatGPT about Object Relational Mapping tools (ORMs).&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/max-harlynking-lve-gF3p9nE-unsplash.jpg" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="prompt-give-arguments-for-and-against-using-an-orm-to-generate-database-code"&gt;Prompt: Give Arguments for and Against Using an ORM to Generate Database Code&lt;/h2&gt;
&lt;p&gt;As someone who generally sits closer to database code than to application code, I&amp;rsquo;ve often wondered, &amp;ldquo;Why do developers love ORMs &lt;em&gt;so much&lt;/em&gt;?&amp;rdquo; I get the basics: it can make getting started a lot faster. But since I haven&amp;rsquo;t actually used ORMs hands-on, there&amp;rsquo;s plenty I can learn.&lt;/p&gt;
&lt;p&gt;To start out, I asked ChatGPT to argue for and against using an ORM, specifically in the context of generating database code.&lt;/p&gt;
&lt;p&gt;ChatGPT responded:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Arguments for using an ORM to generate database code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Abstraction: ORMs provide an abstraction layer between the application and the database, making it easier for developers to interact with the database without needing to know the underlying SQL.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Productivity: ORMs can automatically generate common database operations, such as CRUD operations, which can save time and increase productivity for developers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Portability: ORMs can allow developers to work with multiple databases by providing a consistent interface, making it easier to switch between different databases or to change the underlying database technology.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Security: ORMs can help prevent SQL injection attacks by automatically parameterizing queries and escaping user input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintenance: ORMs can automatically handle database schema changes, making it easier to maintain the application over time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Arguments against using an ORM to generate database code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Performance: ORMs can add an additional layer of overhead and may negatively impact performance, especially for complex or large datasets.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complexity: ORMs can add complexity to the codebase, making it harder to troubleshoot and maintain the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flexibility: ORMs may not provide the same level of flexibility as writing raw SQL, making it harder to optimize performance or take advantage of specific features of a particular database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learning curve: ORMs can have a steep learning curve for developers who are not familiar with them, making it harder for new developers to understand the codebase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Obscurity: ORMs can obscure the underlying database operations, making it harder for developers to understand how the application is interacting with the database.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;m more familiar with the arguments &lt;em&gt;against&lt;/em&gt; using ORMs to generate database code, but I was still pretty impressed with this as a general summary of two different perspectives.&lt;/p&gt;
&lt;h2 id="prompt-what-are-the-challenges-with-combining-an-orm-with-custom-stored-procedures"&gt;Prompt: What Are the Challenges With Combining an ORM With Custom Stored Procedures?&lt;/h2&gt;
&lt;p&gt;Digging in a little, one thing that can be frustrating is hitting a performance problem when an ORM is generating a bad query. One can often rewrite the query and it will perform much better, but then you hit the question: how do you tell the ORM to use different syntax? One option is to combine the ORM with procedures.&lt;/p&gt;
&lt;p&gt;A lot of folks say this isn&amp;rsquo;t always doable and introduces problems. I asked ChatGPT what those problems might be.&lt;/p&gt;
&lt;p&gt;ChatGPT responded:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Integration: Integrating ORMs with custom stored procedures can be challenging, as the ORM may not be designed to work seamlessly with stored procedures, and the developer may need to write additional code to handle the integration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mapping: ORMs rely on a mapping between the application&amp;rsquo;s data model and the database schema, and stored procedures can make this mapping more complex, as the ORM may not be able to automatically map the output of a stored procedure to the application&amp;rsquo;s data model.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Performance: Stored procedures can provide better performance than dynamically generated SQL in some cases, but executing stored procedures through an ORM can add an additional layer of overhead and may negatively impact performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Debugging: Debugging issues that arise from the integration of ORMs and stored procedures can be challenging, as the ORM may not provide detailed information about the execution of stored procedures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintenance: Stored procedures can make it harder to maintain the application over time, as changes to the stored procedures may require changes to the ORM&amp;rsquo;s codebase, and vice versa.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Portability: ORMs allow to work with multiple databases, but if your application relies on a lot of stored procedures, it may limit the ability to switch between different databases or to change the underlying database technology without rewriting the stored procedures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id="prompt-are-there-tools-or-processes-that-can-make-it-easier-to-combine-orms-with-other-programming-models-for-database-code"&gt;Prompt: Are There Tools or Processes That Can Make It Easier to Combine ORMs With Other Programming Models for Database Code?&lt;/h2&gt;
&lt;p&gt;Confession: I don&amp;rsquo;t think I&amp;rsquo;ve ever asked a human this. I probably should have, but for various reasons I never had time to fit it into a conversation. So I asked a language-generating web page.&lt;/p&gt;
&lt;p&gt;ChatGPT responded:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Code Generation: Some ORMs include code generation tools that can automatically generate code for stored procedures, views, and other database objects. This can make it easier to integrate the ORM with existing database code.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Data Access Layers: Creating a data access layer (DAL) that sits between the ORM and the application code can make it easier to handle the integration of the ORM with other programming models. The DAL can handle the execution of stored procedures and other custom database code, and provide a consistent interface for the application code to interact with the ORM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stored Procedures Wrappers: Some ORM frameworks provide wrappers that allow developers to call stored procedures as if they were regular functions, this way the ORM can handle the integration and provide a consistent interface for the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ORM-agnostic libraries: Some libraries can be used to provide a consistent interface for working with databases, regardless of the ORM in use. This can make it easier to switch between ORMs or to work with multiple ORMs in the same codebase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Third-party libraries: There are third-party libraries that can provide additional functionality to the ORM like stored procedures support, this way the ORM can provide the abstraction layer and the third-party library can provide the stored procedures support.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It&amp;rsquo;s important to note that these tools and processes can vary based on the specific ORM and programming models you are using, and some may be more effective than others depending on the requirements of your application.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hmmm, it seems like there&amp;rsquo;s no easy answers, but these pointers are interesting things that I could explore in a real world problem solving situation.&lt;/p&gt;
&lt;h2 id="prompt-what-are-the-major-improvements-that-have-happened-in-orm-tools-over-time-specifically-related-to-database-code"&gt;Prompt: What Are the Major Improvements That Have Happened in ORM Tools Over Time, Specifically Related to Database Code?&lt;/h2&gt;
&lt;p&gt;Lastly, I considered that technology, including ORMs change fast, and improvements are often made. I asked ChatGPT how ORM tooling has improved over time when it comes to generating database code.&lt;/p&gt;
&lt;p&gt;ChatGPT responded:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Over time, ORM tools have undergone various improvements related to database code, some of the major improvements include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Performance: ORMs have become more efficient at generating and executing database code, and many now include features such as caching and lazy loading to improve performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for multiple databases: ORMs have become more flexible and now support a wide range of databases, this allows developers to work with multiple databases using the same ORM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for stored procedures and views: ORMs have improved their support for stored procedures and views, allowing developers to use these database objects in a more seamless way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Better support for complex queries: ORMs have improved their ability to handle complex queries and joins, allowing developers to write more sophisticated queries with the ORM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improved support for migrations: ORMs have improved their support for database migrations, allowing developers to easily make changes to the database schema over time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Better support for NoSQL databases: ORMs have improved their support for NoSQL databases, allowing developers to use ORMs to work with NoSQL databases in a similar way to how they would work with traditional relational databases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More advanced features: ORMs have added more advanced features like multi-tenancy, sharding, and other features that are specific to certain databases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Better integration with other technologies: ORMs have improved their integration with other technologies like caching systems, search engines, and queues, allowing developers to leverage these technologies in a more seamless way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Better support for testing: ORMs have improved their support for testing, allowing developers to create test data and perform testing in a more efficient way.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&amp;rsquo;s important to note that these improvements have happened over time, and are not all present in all ORM tools, and some ORM may have more or less improvements in certain areas.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="we-need-to-check-our-facts-and-check-our-blind-spots"&gt;We Need to Check Our Facts and Check Our Blind Spots&lt;/h2&gt;
&lt;p&gt;Tools like ChatGPT (and tools like ORMs) don&amp;rsquo;t understand things like humans do. They don&amp;rsquo;t imagine things, they don&amp;rsquo;t lie, they just &amp;hellip; make stuff up. Sometimes it can go very badly.&lt;/p&gt;
&lt;p&gt;We need to use them carefully, and we need to work to improve them. But maybe, if we use them carefully, and if we focus on learning from humans, checking our facts, and looking for our blind spots, they can help us learn and grow.&lt;/p&gt;</description></item><item><title>3 Lessons Learned About Azure SQL Database</title><link>https://kendralittle.com/2023/01/15/azure-sql-database-nuances-forget/</link><pubDate>Sun, 15 Jan 2023 13:02:14 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2023/01/15/azure-sql-database-nuances-forget/</guid><description>&lt;p&gt;Hosted cloud databases make a lot of administrative tasks easier, or take care of them for you altogether.&lt;/p&gt;
&lt;p&gt;But here are three things that I&amp;rsquo;ve found a little too easy to forget about Azure SQL Database.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/andrea-de-santis-zwd435-ewb4-unsplash.jpg"
alt="Abstract or architectural image representing Azure SQL Database concepts" width="240"&gt;
&lt;/figure&gt;
&lt;h2 id="1-service-objective-means-compute-size"&gt;1. &amp;ldquo;Service Objective&amp;rdquo; Means &amp;ldquo;Compute Size&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;When I think about service objectives, I tend to assume we&amp;rsquo;re talking about guaranteed uptime, often expressed in some number of 9&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;But Azure SQL Database has its own language. The best resource I know of to learn that language is the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/glossary-terms"&gt;Azure SQL glossary of terms&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The glossary defines service objective this way:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Compute size (service objective) is the amount of CPU, memory, and storage resources available for a single database or elastic pool. Compute size also defines resource consumption limits, such as maximum IOPS, maximum log rate, etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you are choosing your compute size, you are generally &lt;em&gt;not&lt;/em&gt; presented with a slider that shows the amount of memory your database will get. You need to take some extra effort to look it up in the docs. This is worth doing, because&amp;hellip;&lt;/p&gt;
&lt;h2 id="2-database-memory-is-pretty-darn-limited-and-serverless-compute-has-even-less-memory"&gt;2. Database Memory Is Pretty Darn Limited, and Serverless Compute Has Even Less Memory&lt;/h2&gt;
&lt;p&gt;When you configure an Azure SQL Database in the Azure Portal, you choose a lot of things &amp;mdash; but you never choose directly how much memory your database has. The amount of memory allocated to your database is determined by the pricing model and other options you choose.&lt;/p&gt;
&lt;p&gt;If the database memory amount is displayed anywhere in the portal, I haven&amp;rsquo;t found it yet. I believe you have to know to go look in the documentation for resource limits, which are listed separately for the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/resource-limits-vcore-single-databases"&gt;vCore purchasing model&lt;/a&gt; and the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/resource-limits-dtu-single-databases"&gt;DTU purchasing model&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, as of this writing, under the vCore purchasing model using the General Purpose service tier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8 vCores with Serverless compute (standard series Gen5) gets 24 GB max memory&lt;/li&gt;
&lt;li&gt;8 vCores with Provisioned compute (standard series Gen5) gets 41.5 GB max memory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do both of these memory limits seem terribly small to me for 8 vCores? Yes.&lt;/p&gt;
&lt;p&gt;I suspect that if you say you want to increase your cache size only without adjusting other elements of compute, the Azure answer is that you should look into implementing something like a Redis cache. :shrug:&lt;/p&gt;
&lt;h2 id="3-there-aint-simple-autogrowth-here-friend-and-an-application-may-not-throw-the-correct-error-when-youre-out-of-space"&gt;3. There Ain&amp;rsquo;t Simple Autogrowth Here, Friend, and an Application May Not Throw the Correct Error When You&amp;rsquo;re Out of Space&lt;/h2&gt;
&lt;p&gt;I remember when I first started as a DBA, early on my team hit an issue where an application was failing and we needed to figure out why. We determined that the database files were out of space. It took time to discover because the error message that bubbled up in the application was completely unrelated and was a red herring.&lt;/p&gt;
&lt;p&gt;Some things never change, especially the &amp;ldquo;misleading error message&amp;rdquo; part.&lt;/p&gt;
&lt;p&gt;Your Azure SQL Database settings control the maximum size for your database. Increasing the max size within your current service level object can be relatively cheap, compared to increasing vCore count, but it&amp;rsquo;s still something you need to manage yourself: there isn&amp;rsquo;t a simple &amp;ldquo;enable autogrowth&amp;rdquo; checkbox.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth setting up database monitoring and configuring alerts for the amount of space used / free space in your database files. You should also periodically review the maximum data size allowed for your SLO (&lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/resource-limits-vcore-single-databases"&gt;vCore&lt;/a&gt; / &lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/resource-limits-dtu-single-databases"&gt;DTU&lt;/a&gt;) in the resource limits and compare this to projections of how much space you&amp;rsquo;ll likely need for a time period, in case you&amp;rsquo;re at risk of needing more space than your configuration allows: upgrading your core count is generally pricier than moving the database storage size slider.&lt;/p&gt;</description></item><item><title>New Article on Performance Tuning with the Missing Indexes Feature in SQL Server</title><link>https://kendralittle.com/2022/03/18/missing-indexes-sql-server/</link><pubDate>Fri, 18 Mar 2022 08:06:28 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2022/03/18/missing-indexes-sql-server/</guid><description>&lt;p&gt;We&amp;rsquo;ve just published a new article in the SQL docs, &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/indexes/tune-nonclustered-missing-index-suggestions"&gt;Tune nonclustered indexes with missing index suggestions
&lt;/a&gt;. The article explains what the missing index feature is, limitations of the feature, and how to use missing index DMVs and missing index suggestions in Query Store to tune indexes.&lt;/p&gt;
&lt;h2 id="why-now"&gt;Why Now?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/maksym-kaharlytskyi-Q9y3LRuuxmg-unsplash.jpg"
alt="Abstract geometric pattern with blue and orange tones" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;The missing indexes feature has been around in SQL Server since (looks at watch) SQL Server 2005. Seventeen years later, we&amp;rsquo;ve added a new article on using the feature. Why?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our partners in Microsoft Customer Service and Support let us know that we needed more guidance for customers in the documentation on using missing indexes. (Thanks to Joseph Pilov.)&lt;/li&gt;
&lt;li&gt;I found that &lt;a href="https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms345485(v=sql.105)"&gt;older guidance on using the feature&lt;/a&gt; had been archived. (How did I find the archived content? A link from &lt;a href="https://www.brentozar.com/archive/2013/07/dude-who-stole-my-missing-index-recommendation"&gt;one of my old blog posts&lt;/a&gt;. Blogging is forever my long-term memory.)&lt;/li&gt;
&lt;li&gt;The older guidance was good, but didn&amp;rsquo;t mention some of the gotchas that can come with working with missing index requests: things like only one missing index request scripting from a query plan in SSMS, even if multiple requests were present in the query plan XML.&lt;/li&gt;
&lt;li&gt;New features like Query Store have been released since the archived guidance was written. Query Store helps persist missing index requests across index maintenance, restarts/failovers, recompiles, and memory pressure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All this considered, it made sense to use the archived guidance as a reference to put together a new article on using missing index requests to tune queries.&lt;/p&gt;
&lt;h2 id="what-else-may-come"&gt;What Else May Come?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d like to write a complimentary article on tuning indexes with the Query Store. This will be an example of looking at a workload in Query Store, and using information both from missing indexes and from the execution plans to tune queries.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn More&lt;/h2&gt;
&lt;p&gt;Coincidentally, Erik Darling also published an article on missing indexes this week. Check out &lt;a href="https://www.erikdarlingdata.com/sql-server/understand-your-plan-missing-index-requests/"&gt;Understand Your Plan: Missing Index Requests&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="got-suggestions-for-the-missing-indexes-article"&gt;Got Suggestions for the Missing Indexes Article?&lt;/h2&gt;
&lt;p&gt;If you see something you&amp;rsquo;d like to change on the missing indexes article, there are two options to share it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scroll down to the &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/indexes/tune-nonclustered-missing-index-suggestions#next-steps"&gt;bottom of the article&lt;/a&gt; to the &amp;ldquo;Submit and view feedback&amp;rdquo; box. Select &amp;ldquo;This page&amp;rdquo;, and fill out an issue with your suggestion.&lt;/li&gt;
&lt;li&gt;Make a suggestion in a pull request. To learn how, see &lt;a href="https://docs.microsoft.com/en-us/sql/sql-server/sql-server-docs-contribute"&gt;How to contribute to SQL Server documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Find Query Execution Timeouts with Query Store</title><link>https://kendralittle.com/2022/03/11/find-execution-timeouts-query-store/</link><pubDate>Fri, 11 Mar 2022 09:01:08 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2022/03/11/find-execution-timeouts-query-store/</guid><description>&lt;p&gt;During a discussion of troubleshooting query timeouts in Azure SQL Database recently, I wondered: can you find queries that timed out in Query Store?&lt;/p&gt;
&lt;p&gt;You can.&lt;/p&gt;
&lt;h2 id="query-timeout-essentials"&gt;Query Timeout Essentials&lt;/h2&gt;
&lt;p&gt;Here are some basics regarding query timeouts for SQL Server, Azure SQL Database, and Azure SQL Managed Instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Execution timeouts are NOT set or enforced by the database engine. It is happy to wait for your query to run or for your transaction to be open for hours, days, or years, until you commit, cancel, or get disconnected.&lt;/li&gt;
&lt;li&gt;Timeouts are set by the calling application. If you don&amp;rsquo;t explicitly set a timeout on your connection string, there is generally a default timeout that is used. Often, this is 30 seconds for query execution timeouts.&lt;/li&gt;
&lt;li&gt;Connection timeouts are different than execution timeouts. If you see a connection timeout, often this is a firewall or network issue preventing you from connecting to the database (or perhaps it&amp;rsquo;s even offline). Execution timeouts are when the calling application doesn&amp;rsquo;t want to wait any more for a query to complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-traditional-way-of-finding-query-timeouts"&gt;The Traditional Way of Finding Query Timeouts&lt;/h2&gt;
&lt;p&gt;If you start seeing query execution timeouts from an application, you don&amp;rsquo;t always get information about exactly what query had the problem in the error. The first steps are often to identify that query.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;classic&amp;rdquo; way to do this is to run a trace against your database, using either classic SQL Trace (perhaps with Profiler), or an Extended Events trace. You trace to find an &lt;code&gt;Attention&lt;/code&gt; event, which is also known as &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/errors-events/mssqlserver-3617-database-engine-error"&gt;Error 3617&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t a bad way to go about things, but it&amp;rsquo;s time consuming and inconvenient: you generally only start tracing &lt;em&gt;after&lt;/em&gt; you get a timeout error, and then you need to wait for the issue to happen again.&lt;/p&gt;
&lt;h2 id="finding-timeouts-in-query-store"&gt;Finding Timeouts in Query Store&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-set-options#e-enable-the-query-store"&gt;enabled Query Store&lt;/a&gt;, you may be able to find timeouts immediately, without running a trace.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a caveat here: Query Store doesn&amp;rsquo;t necessarily collect every query. The &lt;code&gt;QUERY_CAPTURE_MODE&lt;/code&gt; &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-set-options#query_capture_mode--all--auto--custom--none-"&gt;setting&lt;/a&gt; may be set to &lt;code&gt;AUTO&lt;/code&gt;, which works to balance the space taken up by plans and doesn&amp;rsquo;t necessarily capture all queries.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s cause a quick timeout and view it in Query Store.&lt;/p&gt;
&lt;h3 id="reproducing-a-query-execution-timeout"&gt;Reproducing a Query Execution Timeout&lt;/h3&gt;
&lt;p&gt;SQL Server Management Studio conveniently lets you set an execution timeout in the session options when you connect to a database. We&amp;rsquo;re going to take advantage of this to reproduce an execution timeout. I&amp;rsquo;m using the &lt;a href="https://www.microsoft.com/en-us/download/details.aspx?id=18279"&gt;ContosoRetailDW&lt;/a&gt; database for this example, but you can adapt this pattern to any database suitable for testing (where blocking and possible data loss are OK).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve enabled Query Store on the database with the following options:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ContosoRetailDW&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OPERATION_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;READ_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEANUP_POLICY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;STALE_QUERY_THRESHOLD_DAYS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_FLUSH_INTERVAL_SECONDS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_STORAGE_SIZE_MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INTERVAL_LENGTH_MINUTES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE_BASED_CLEANUP_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_PLANS_PER_QUERY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WAIT_STATS_CAPTURE_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_CAPTURE_MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;ALL&lt;/strong&gt; may not be the best &lt;code&gt;QUERY_CAPTURE_MODE&lt;/code&gt; for production databases: in this case, it&amp;rsquo;s useful when I don&amp;rsquo;t have a real workload running. I&amp;rsquo;ve also raised the database compat level of the database, because this puppy is super old and I want to use &lt;code&gt;TRY_CONVERT&lt;/code&gt; syntax in a query later.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ContosoRetailDW&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPATIBILITY_LEVEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, connect a session to the database. Don&amp;rsquo;t mess with the execution timeouts on this session, leave it at unlimited. Run a command like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;OnlineSalesKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;OnlineSalesKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnlineSalesKey&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FactOnlineSales&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UPDLOCK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, connect a second session. In the connection dialog, select &lt;strong&gt;Options&amp;raquo;&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ssms-connect-options.png"
alt="Screenshot of the connection dialog in SSMS. The options button is highlighted."&gt;
&lt;/figure&gt;
&lt;p&gt;In the connection options dialog, set &lt;strong&gt;Execution time-out&lt;/strong&gt; to &lt;strong&gt;5&lt;/strong&gt; seconds.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ssms-connect-execution-time-out.png"
alt="Screenshot of the connection options dialog in SSMS. Execution time-out is set to 5."&gt;
&lt;/figure&gt;
&lt;p&gt;Select &lt;strong&gt;Connect&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Run the following query in this session:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FactOnlineSales&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This query will be blocked by the query with the open transaction. After five seconds, you should see the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg -2, Level 11, State 0, Line 0
Execution Timeout Expired. The timeout period elapsed prior to
completion of the operation or the server is not responding.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, back in the first session, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="find-the-timeout-in-query-store"&gt;Find the Timeout in Query Store&lt;/h3&gt;
&lt;p&gt;To find timeouts in Query Store, you want to look for queries where &lt;code&gt;execution_type&lt;/code&gt; in &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-query-store-runtime-stats-transact-sql"&gt;sys.query_store_runtime_stats&lt;/a&gt; is set to 3. Note that this isn&amp;rsquo;t &lt;strong&gt;only&lt;/strong&gt; query timeouts: this status indicates &amp;lsquo;Client initiated aborted execution&amp;rsquo;. But in my testing I find that this includes query timeouts.&lt;/p&gt;
&lt;p&gt;Here is a sample query against the Query Store DMVs looking for this status:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execution_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execution_type_desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan_xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qst&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OUTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan_xml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY_CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qpx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execution_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s a screenshot of the results I see in SSMS for this query:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ssms-query-store-timeouts.png"
alt="Screenshot of the query being run in SSMS with three rows returned."&gt;
&lt;/figure&gt;
&lt;p&gt;I clicked the &amp;ldquo;cancel executing query&amp;rdquo; button for the queries on rows 2 and 3 of this result set. The query on row 1 was run twice with the execution time-out setting in SSMS set to 5 seconds when I had the table locked in another session.&lt;/p&gt;
&lt;h2 id="this-isnt-perfect-but-its-worth-checking"&gt;This Isn&amp;rsquo;t Perfect, but It&amp;rsquo;s Worth Checking&lt;/h2&gt;
&lt;p&gt;As I mentioned, you probably don&amp;rsquo;t want to capture all queries in Query Store in a production database. When timeouts strike, there&amp;rsquo;s no guarantee that Query Store has a record of the query. (This is true for all monitoring systems, really: there&amp;rsquo;s a performance tradeoff in observing things incredibly closely!)&lt;/p&gt;
&lt;p&gt;However, if you have Query Store enabled, I definitely think it&amp;rsquo;s worth checking it for information regarding timeouts, as it&amp;rsquo;s a pretty quick and painless process to do so. If it doesn&amp;rsquo;t have the timeout data you&amp;rsquo;re looking for, you can always start up a trace and look for those &lt;code&gt;Attention&lt;/code&gt; events as usual.&lt;/p&gt;
&lt;h2 id="theres-a-lot-more-cool-things-in-query-store"&gt;There&amp;rsquo;s a Lot More Cool Things in Query Store&lt;/h2&gt;
&lt;p&gt;Query Store is an interesting thing. It doesn&amp;rsquo;t replace monitoring systems: if your database is inaccessible, you can&amp;rsquo;t get to Query Store to figure out what&amp;rsquo;s wrong. It doesn&amp;rsquo;t alert you as to downtime or availability, that&amp;rsquo;s not its purpose.&lt;/p&gt;
&lt;p&gt;However, Query Store does replace a lot of the performance tuning aspects of monitoring systems. It certainly can allow you to go cheaper on a monitoring solution and primarily look for availability monitoring, while doing most of your tuning and troubleshooting with Query Store.&lt;/p&gt;</description></item><item><title>Index Design Guide Updated: Index Types, B+ Trees, and Row Locators, Oh My</title><link>https://kendralittle.com/2022/02/23/index-design-guide-updated-btrees-row-locators/</link><pubDate>Wed, 23 Feb 2022 08:38:18 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2022/02/23/index-design-guide-updated-btrees-row-locators/</guid><description>&lt;p&gt;We&amp;rsquo;ve recently updated the &lt;a href="https://docs.microsoft.com/sql/relational-databases/sql-server-index-design-guide"&gt;SQL Server and Azure SQL index architecture and design guide&lt;/a&gt;. This article is an in-depth guide to indexing in databases using the SQL Server engine, including SQL Server, Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics.&lt;/p&gt;
&lt;p&gt;Our recent update adds a table to categorize the types of indexes discussed in the article, clarifies B-trees vs B+ trees, and describes how row locators (aka &amp;ldquo;secret columns&amp;rdquo;) are used in nonclustered indexes.&lt;/p&gt;
&lt;h2 id="new-table-summarizing-types-of-indexes"&gt;New Table Summarizing Types of Indexes&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/sql-server-index-design-guide"&gt;index architecture and design guide&lt;/a&gt; now opens with a table describing the types indexes discussed in the article, grouped by their primary storage format: disk-based rowstore indexes, columnstore indexes, and memory-optimized indexes.&lt;/p&gt;
&lt;p&gt;This is a small change, but I hope it proves helpful to folks who are newer to this topic and who may find themselves confused by different uses of the word &amp;rsquo;nonclustered&amp;rsquo;, or who want a big-picture view of the most commonly used index types.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-architecture-design-guide-types-indexes.png"
alt="Screenshot of the new table describing index types by primary storage format" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="clarifying-b-trees-vs-b-trees"&gt;Clarifying B Trees vs B+ Trees&lt;/h2&gt;
&lt;p&gt;A customer submitted an issue asking us to clarify when the SQL Server engine uses B-trees vs B+ trees. Up to this point, the documentation for SQL Server and Azure SQL has largely used the general term &amp;ldquo;B-tree&amp;rdquo; without being more specific.&lt;/p&gt;
&lt;p&gt;My colleague Mike Ray (&lt;a href="https://twitter.com/mncray"&gt;Twitter&lt;/a&gt;) took on this project, which was a considerable amount of work: there are a &lt;em&gt;lot&lt;/em&gt; of articles which mention B-trees. Most of these articles shouldn&amp;rsquo;t go into a deep discussion of types of B-trees, however. Mike identified these articles (for example, the &lt;a href="https://docs.microsoft.com/sql/t-sql/statements/create-index-transact-sql"&gt;CREATE INDEX (Transact-SQL)&lt;/a&gt; article) and added the following note:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SQL Server documentation uses the term B-tree generally in reference to indexes. In rowstore indexes, SQL Server implements a B+ tree. This does not apply to columnstore indexes or in-memory data stores. Review &lt;a href="https://docs.microsoft.com/sql/relational-databases/sql-server-index-design-guide"&gt;SQL Server Index Architecture and Design Guide&lt;/a&gt; for details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mike worked with Pedro Lopes (&lt;a href="https://twitter.com/SQLPedro"&gt;Twitter&lt;/a&gt;) to update the index architecture and design guide to clarify when B+ indexes are used (disk-based rowstore indexes, the deltastore for columnstore indexes) and when other variations of B-trees are used (a Bw-tree is used in In-Memory nonclustered indexes).&lt;/p&gt;
&lt;p&gt;Together, these changes should not only help folks who are interested in B-trees, but also will help raise awareness of the index architecture and design guide itself as a great free resource for learning about indexing.&lt;/p&gt;
&lt;h2 id="describing-row-locators-aka-secret-columns-in-nonclustered-indexes"&gt;Describing Row Locators (aka &amp;ldquo;Secret Columns&amp;rdquo;) in Nonclustered Indexes&lt;/h2&gt;
&lt;p&gt;Another customer submitted an issue asking us to document how and why the SQL Server Engine adds clustered index keys to nonclustered indexes.&lt;/p&gt;
&lt;p&gt;Based on this request, I worked with Pedro to add information to the &lt;a href="https://docs.microsoft.com/sql/relational-databases/sql-server-index-design-guide?#nonclustered-index-architecture"&gt;nonclustered index architecture&lt;/a&gt; section of the design guide.&lt;/p&gt;
&lt;p&gt;We went a little broader than the request, because if a disk-based rowstore table does not have a clustered index (in other words, if it is a heap), then a row locator is still added to nonclustered indexes. We added the following table, along with a table of specific examples.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-architecture-design-guide-row-locators.png"
alt="Screenshot of the new table describing index types by primary storage format" width="600"&gt;
&lt;/figure&gt;
&lt;p&gt;And, importantly, we added the following sentence:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Clustered index key-based row locator columns in a nonclustered index can be used by the query optimizer, regardless of whether they were explicitly specified in the index definition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="thanks-to-pedro-lopes-and-mike-ray"&gt;Thanks to Pedro Lopes and Mike Ray&lt;/h2&gt;
&lt;p&gt;Thanks very much to my colleagues Mike Ray (&lt;a href="https://twitter.com/mncray"&gt;Twitter&lt;/a&gt;) and Pedro Lopes (&lt;a href="https://twitter.com/SQLPedro"&gt;Twitter&lt;/a&gt;) for their efforts in helping make the &lt;a href="https://docs.microsoft.com/sql/relational-databases/sql-server-index-design-guide"&gt;SQL Server and Azure SQL index architecture and design guide&lt;/a&gt; even better.&lt;/p&gt;</description></item><item><title>Workers vs. Requests in Azure SQL Database</title><link>https://kendralittle.com/2022/01/18/workers-requests-azure-sql-database/</link><pubDate>Tue, 18 Jan 2022 17:36:30 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2022/01/18/workers-requests-azure-sql-database/</guid><description>&lt;p&gt;We now explicitly define &amp;lsquo;requests&amp;rsquo; and &amp;lsquo;workers&amp;rsquo; in the Azure SQL Database documentation, and we&amp;rsquo;ve cleaned up multiple places where we used to equate the two terms. In this post, I share the history of the two terms when it comes to Azure SQL Database, why the two were ever equated, and why things like this are tricky to change.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/john-anvik-tZIrJ3CgK_Y-unsplash.jpg"
alt="Abstract architectural image with geometric patterns" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="what-we-changed"&gt;What We Changed&lt;/h2&gt;
&lt;p&gt;The documentation for Azure SQL Database previously contained some statements which equate workers and requests. Notice that this heading equates workers and requests, but the paragraph talks only about worker limits:&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4 id="sessions-and-workers-requests"&gt;Sessions and workers (requests)&lt;/h4&gt;
&lt;p&gt;The maximum numbers of sessions and workers are determined by the service tier and compute size. New requests are rejected when session or worker limits are reached, and clients receive an error message.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The documentation also has tables which explain resource limits by service tier and compute size. Those tables used to look like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/max-current-workers-requests.png"
alt="Screenshot of a table from Azure SQL Database documentation showing resource limits that equated workers and requests" width="700"&gt;&lt;figcaption&gt;
&lt;p&gt;An example table equating workers and requests&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="what-are-workers-and-requests-anyway"&gt;What Are Workers and Requests, Anyway?&lt;/h2&gt;
&lt;p&gt;We made changes to clarify that there is no limit on requests. Instead, there is a &lt;em&gt;worker&lt;/em&gt; limit. We also added information to help folks troubleshoot situations where they approach or hit worker limits.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We now &lt;a href="https://docs.microsoft.com/azure/azure-sql/database/resource-limits-logical-server"&gt;define sessions, requests, and workers&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;A session represents a process connected to the database engine.&lt;/li&gt;
&lt;li&gt;A request is the logical representation of a query or batch. A request is issued by a client connected to a session. Over time, multiple requests may be issued on the same session.&lt;/li&gt;
&lt;li&gt;A worker thread, also known as a worker or thread, is a logical representation of an operating system thread. A request may have many workers when executed with a parallel query execution plan, or a single worker when executed with a serial (single threaded) execution plan. Workers are also required to support activities outside of requests: for example, a worker is required to process a login request as a session connects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;p&gt;We&amp;rsquo;ve also cleaned up the tables: where tables used to read &amp;lsquo;workers (requests)&amp;rsquo;, they now simply read &amp;lsquo;workers&amp;rsquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, we added more troubleshooting steps for when the worker limit has been reached under &lt;a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/troubleshoot-common-errors-issues#error-10928-resource-id--1-the-request-limit-for-the-database-is-d-and-has-been-reached"&gt;Error 10928: Resource ID : 1. The request limit for the database is %d and has been reached&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice that this error message still uses the word &amp;lsquo;requests&amp;rsquo;: keep reading to learn why.&lt;/p&gt;
&lt;h2 id="why-were-workers-and-requests-ever-equated-for-azure-sql-database"&gt;Why Were Workers and Requests Ever Equated for Azure SQL Database?&lt;/h2&gt;
&lt;p&gt;We added &lt;a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/troubleshoot-common-errors-issues#error-10928-resource-id--1-the-request-limit-for-the-database-is-d-and-has-been-reached"&gt;a note&lt;/a&gt; below that error message which explains:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The initial offering of Azure SQL Database supported only single threaded queries. At that time, the number of requests was always equivalent to the number of workers. Error message 10928 in Azure SQL Database contains the wording &amp;ldquo;The request limit for the database is N and has been reached&amp;rdquo; for backwards compatibility purposes. The limit reached is actually the number of workers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-was-this-tricky-to-change"&gt;Why Was This Tricky to Change?&lt;/h2&gt;
&lt;p&gt;When Azure SQL Database gained the ability to run parallel queries, requests and workers were no longer interchangeable at all: a single request may have a large amount of workers, depending on the query plan and level of parallelism.&lt;/p&gt;
&lt;p&gt;But things like that error message are risky to change. One of the big requirements of providing a hosted database service is providing as much stability as possible while still innovating. Customers can, and do, sometimes code dependencies on the text of error messages (not just the number). Changing something even as simple as an error message can cause regressions.&lt;/p&gt;
&lt;p&gt;The documentation attempted to strike a balance here: headings and tables were adjusted to say &amp;ldquo;workers&amp;rdquo; with the older term &amp;ldquo;(requests)&amp;rdquo; following in parentheses, while explanatory paragraphs talked only about the request limit.&lt;/p&gt;
&lt;h2 id="why-we-updated-the-docs-further"&gt;Why We Updated the Docs Further&lt;/h2&gt;
&lt;p&gt;Feedback came in over the last few months that the documentation wasn&amp;rsquo;t striking the balance as intended: this was confusing. Based on that feedback, we made the changes above to clearly define the terms involved, explain and support folks hitting worker limits, and simplify the resource limits tables.&lt;/p&gt;
&lt;p&gt;Thanks very much to &lt;a href="https://twitter.com/DimitriFurman"&gt;Dimitri Furman&lt;/a&gt; for his help in working out these changes.&lt;/p&gt;</description></item><item><title>What I Learned Writing About How to Diagnose and Troubleshoot High CPU in Azure SQL Database</title><link>https://kendralittle.com/2022/01/05/what-i-learned-writing-diagnose-and-troubleshoot-high-cpu-azure-sql-database/</link><pubDate>Wed, 05 Jan 2022 10:56:52 -0500</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2022/01/05/what-i-learned-writing-diagnose-and-troubleshoot-high-cpu-azure-sql-database/</guid><description>&lt;p&gt;Writing helps me learn. In my job as a Content Developer, this is more true than ever: there&amp;rsquo;s a fantastic group of folks, both in the Database Docs team and in the Microsoft Data Platform engineering team, who review and contribute to content.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve just had the pleasure of publishing my first new article in the Microsoft Docs, &lt;a href="https://docs.microsoft.com/azure/azure-sql/database/high-cpu-diagnose-troubleshoot"&gt;Diagnose and troubleshoot high CPU on Azure SQL Database&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/manuel-CANL3bzp6wU-unsplash.jpg"
alt="Close up image of a CPU" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;This article isn&amp;rsquo;t really &amp;ldquo;mine&amp;rdquo;: anyone in the community can create a Pull Request to suggest changes, or others at Microsoft may take it in a different direction. But I got to handle the outlining, drafting, and incorporation of suggested changes for the initial publication.&lt;/p&gt;
&lt;p&gt;It was a ton of fun, and I learned a lot about Azure SQL Database in the process.&lt;/p&gt;
&lt;h2 id="you-can-query-your-vcore-count"&gt;You Can Query Your vCore Count&lt;/h2&gt;
&lt;p&gt;Azure SQL Database lets you choose between two &lt;a href="https://docs.microsoft.com/azure/azure-sql/database/purchasing-models"&gt;purchasing models&lt;/a&gt;: vCore and database transaction unit (DTU).&lt;/p&gt;
&lt;p&gt;One benefit of the vCore model is that understanding and controlling the number of virtual cores allocated to your database is pretty straightforward: there&amp;rsquo;s a slider for the number of cores.&lt;/p&gt;
&lt;p&gt;I did learn, however, that it can be worthwhile to query your virtual core count with Transact-SQL. That&amp;rsquo;s because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You might have more vCores than you think. For databases using Gen4 hardware, the number of schedulers in &lt;code&gt;sys.dm_os_schedulers&lt;/code&gt; may be double the number of vCores specified at database creation and shown in Azure portal.&lt;/li&gt;
&lt;li&gt;If you are using the DTU purchasing model, you don&amp;rsquo;t get to specify the number of cores available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;ve got &lt;a href="https://docs.microsoft.com/azure/azure-sql/database/high-cpu-diagnose-troubleshoot#identify-vcore-count-with-transact-sql"&gt;a simple query in the article&lt;/a&gt; which will return your current vCore count for a database.&lt;/p&gt;
&lt;h2 id="you-can-switch-between-insights-in-the-azure-portal-and-query-store"&gt;You Can Switch Between Insights in the Azure Portal and Query Store&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a nice area in the Azure portal called &lt;strong&gt;Query Performance Insight&lt;/strong&gt;. You can see how much CPU was used over time along with top queries that ran in that time period.&lt;/p&gt;
&lt;p&gt;I like this view and find it pretty easy to navigate. I had a theory that the query information was coming from Query Store, but I wasn&amp;rsquo;t certain. I found that in fact, it is: you can take the query ids from the portal and plug them into the graphic Query Store tools in SQL Server Management Studio (SSMS) and dig into query execution plans and historic execution stats that way. I like that these can work together.&lt;/p&gt;
&lt;h2 id="in-flight-execution-statistics-are-enabled-by-default-in-query-plans"&gt;&amp;ldquo;In Flight&amp;rdquo; Execution Statistics Are Enabled by Default in Query Plans&lt;/h2&gt;
&lt;p&gt;This is something that&amp;rsquo;s been around for a little while, but I missed that this became available by default. There&amp;rsquo;s a DMV, &lt;a href="https://docs.microsoft.com/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-statistics-xml-transact-sql"&gt;sys.dm_exec_query_statistics_xml&lt;/a&gt;, which returns &amp;ldquo;in flight&amp;rdquo; statistics for execution plans for currently running queries.&lt;/p&gt;
&lt;p&gt;It used to be that you could only see what SQL Server estimated for queries that are currently running. But sometimes estimates are way off: sometimes the optimizer thinks it&amp;rsquo;s only going to get one row back, but it turns out to be millions. Or the opposite might happen. In-flight statistics help you see how many rows have flowed through different parts of a query plan so far.&lt;/p&gt;
&lt;p&gt;In-flight statistics rely on something called &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/query-profiling-infrastructure"&gt;lightweight query execution statistics profiling&lt;/a&gt;. Earlier versions of lightweight profiling can be enabled on SQL Server 2014 or 2016.&lt;/p&gt;
&lt;p&gt;The latest version of &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/query-profiling-infrastructure#lightweight-query-execution-statistics-profiling-infrastructure-v3"&gt;lightweight query execution statistics profiling&lt;/a&gt; is enabled by default on Azure SQL Database and in SQL Server 2019.&lt;/p&gt;
&lt;h2 id="you-can-get-query-compilation-rates-from-query-store"&gt;You Can Get Query Compilation Rates from Query Store&lt;/h2&gt;
&lt;p&gt;There are a few things in SQL Server which I&amp;rsquo;m used to collecting with perfmon counters. That can be handy if you&amp;rsquo;re used to it, but it lacks a level of detail: you get aggregate information about compilation overall, but you don&amp;rsquo;t know which queries were compiling or re-compiling. (And honestly, understanding what gets counted as a compile vs a recompile in perfmon counters is pretty confusing.)&lt;/p&gt;
&lt;p&gt;In researching for the article, I found that you can query compilation rates from Query Store. This is great, because you can dig in and see &lt;em&gt;which&lt;/em&gt; queries are being compiled most frequently during different time periods. You can &lt;a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/high-cpu-diagnose-troubleshoot#query-the-most-frequently-compiled-queries-by-query-hash"&gt;query this with Transact-SQL&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="have-suggestions-for-the-article"&gt;Have Suggestions for the Article?&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;d love to read it! There&amp;rsquo;s two great ways to submit suggestions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select the &amp;lsquo;Edit&amp;rsquo; button at the top right of the page and submit a suggestion via a Pull Request in GitHub. This can be done entirely in the browser, no major GitHub experience is required (although you&amp;rsquo;ll need a free account)&lt;/li&gt;
&lt;li&gt;Head down to the &amp;lsquo;Feedback&amp;rsquo; section at the very bottom of the article and select &amp;lsquo;This page&amp;rsquo;. This will take you to a screen where you can submit a GitHub issue detailing your thoughts. Again, you&amp;rsquo;ll need a free GitHub account for this, but no experience with GitHub is required.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Addressing the Rumors That I Have Been Removed from the MVP Program</title><link>https://kendralittle.com/2021/11/04/working-at-microsoft-senior-content-developer/</link><pubDate>Thu, 04 Nov 2021 16:24:12 -0400</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/11/04/working-at-microsoft-senior-content-developer/</guid><description>&lt;p&gt;I&amp;rsquo;d like to openly and honestly answer &lt;a href="https://twitter.com/erikdarlingdata/status/1456364093854691334"&gt;the rumors&lt;/a&gt; that I have been removed from the Microsoft MVP program.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/joshua-j-cotten-8NmGOkPliE0-unsplash.jpg"
alt="One meercat whispering in the ear of another meercat." width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="firstly-its-true"&gt;Firstly, It&amp;rsquo;s True&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve started a new job at Microsoft. As of Monday, I am now a proud member of the Content Development team which brings you documentation on all things SQL Server and Azure SQL. I will be working with the product team, other Content Developers, and community contributors while focusing on &lt;a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/sql-database-paas-overview"&gt;Azure SQL Database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a Microsoft employee, I&amp;rsquo;m no longer eligible to be a member of the MVP program. It&amp;rsquo;s been a privilege to be an MVP, but this was a job I couldn&amp;rsquo;t resist.&lt;/p&gt;
&lt;h2 id="i-was-not-forced-to-leave-the-united-kingdom"&gt;I Was Not Forced to Leave the United Kingdom&lt;/h2&gt;
&lt;p&gt;Some say I fled Boris Johnson&amp;rsquo;s hair.&lt;/p&gt;
&lt;p&gt;While this is plausible, the truth is that Jeremiah and I have moved back to the United States to be closer to our families. We found that it was very hard traveling across oceans in a global pandemic and decided that the right thing to do was to move back from the UK. It made sense to shift our careers as part of this process.&lt;/p&gt;
&lt;h2 id="why-im-excited-about-my-new-job"&gt;Why I&amp;rsquo;m Excited About My New Job&lt;/h2&gt;
&lt;p&gt;I owe so much of my career to the Microsoft documentation on SQL Server. Hardly a workday has gone by over the last 20 years when I haven&amp;rsquo;t read, shared, discussed, or blogged about these docs. (And in my heart, I will always think of these docs as &amp;lsquo;Books Online&amp;rsquo;.)&lt;/p&gt;
&lt;p&gt;As the SQL Server engine expands and as the Azure SQL offering evolves, the docs continue to help the community learn, grow, and share.&lt;/p&gt;
&lt;p&gt;To me, this is hugely exciting and I&amp;rsquo;m so honored and thrilled to get to work in this space.&lt;/p&gt;
&lt;h2 id="want-to-learn-more-about-the-sql-server-and-azure-sql-docs-team"&gt;Want to Learn More About the SQL Server and Azure SQL Docs Team?&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to learn more about the team or how you can help out with the docs yourself, my teammate &lt;a href="https://twitter.com/william_a_dba"&gt;William Assaf&lt;/a&gt; is giving a session at the upcoming PASS Community Data Summit, &lt;a href="https://passdatacommunitysummit.com/sessions/267107"&gt;Become a Contributor to Microsoft Docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The session is free and takes place on &lt;strong&gt;Thursday, November 11 at 2pm EST&lt;/strong&gt;. There will be an interactive Q&amp;amp;A session with the team following William&amp;rsquo;s 30-minute talk.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;lot&lt;/em&gt; of the work I&amp;rsquo;ll be doing is collaborating with contributors and helping community members suggest changes and improvements to the documentation. Learning how to work in this process is simple. It also builds activity on your GitHub profile which can be a nice feature for your resume. I hope you can join us.&lt;/p&gt;</description></item><item><title>Gotchas with Deferred Name Resolution in SQL Server: Stored Procedures, Synonyms, Views, and Functions</title><link>https://kendralittle.com/2021/10/18/deferred-name-resolution-in-sql-server-stored-procedures-views-functions/</link><pubDate>Mon, 18 Oct 2021 11:14:16 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/10/18/deferred-name-resolution-in-sql-server-stored-procedures-views-functions/</guid><description>&lt;p&gt;Have you ever tried to create an object in SQL Server, but it failed due to a missing table, column, or other dependency? If so, you&amp;rsquo;ve hit a case where SQL Server doesn&amp;rsquo;t offer &amp;lsquo;deferred name resolution&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;While these errors can be helpful when you&amp;rsquo;ve made a typo or accidentally used the wrong database, this can sometimes be a big hassle when you are&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploying database code to set up a partial environment&lt;/li&gt;
&lt;li&gt;Deploying database code from version control to an empty database to ensure the code is valid&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, I walk through common scenarios and test whether deferred name resolution works or not.&lt;/p&gt;
&lt;h2 id="what-is-deferred-name-resolution"&gt;What Is Deferred Name Resolution?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2005/ms190686(v=sql.90)"&gt;Deferred Name Resolution&lt;/a&gt; allows you to create objects in SQL Server without verifying that referenced objects (or referenced columns in objects) exist.&lt;/p&gt;
&lt;p&gt;This is quite a confusing feature because it only works for some types of objects in specific scenarios. Every time I think I understand this feature, I am sure to discover a new gotcha.&lt;/p&gt;
&lt;h2 id="summary-table"&gt;Summary Table&lt;/h2&gt;
&lt;p&gt;I haven&amp;rsquo;t memorized everything in this post, and I don&amp;rsquo;t expect that you will, either. I&amp;rsquo;m creating this as a reference I can revisit when this topic comes up. Here&amp;rsquo;s a summary of when different object types do and do not get deferred name resolution, per my testing:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th style="text-align: center"&gt;Object doesn&amp;rsquo;t exist&lt;/th&gt;
&lt;th style="text-align: center"&gt;Object exists with different columns&lt;/th&gt;
&lt;th style="text-align: center"&gt;Object in an offline database&lt;/th&gt;
&lt;th style="text-align: center"&gt;Object referenced via Linked Server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stored Procedures&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;Sometimes&lt;/td&gt;
&lt;td style="text-align: center"&gt;Usually N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Synonyms&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;td style="text-align: center"&gt;N/A&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Views&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalar Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inline Table Valued Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-Statement Table Valued Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Y&lt;/td&gt;
&lt;td style="text-align: center"&gt;N&lt;/td&gt;
&lt;td style="text-align: center"&gt;Sometimes&lt;/td&gt;
&lt;td style="text-align: center"&gt;Usually N&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;To dig into any area, use the table of contents above to jump to that section for demo code and a comment or two.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/mahdi-bafande-qgJ1rt7TeeY-unsplash.jpg"
alt="A grumpy stuffed plush octopus toy." width="250"&gt;
&lt;/figure&gt;
&lt;h2 id="working-around-a-lack-of-deferred-name-resolution"&gt;Working Around a Lack of Deferred Name Resolution&lt;/h2&gt;
&lt;p&gt;There is no special trick or trace flag which I know of to magically enable deferred name resolution where it doesn&amp;rsquo;t work. However, if you need to deploy code to an empty database or to a partial database environment and it is failing due to missing dependencies, there are a few techniques which you can leverage to help get around the errors.&lt;/p&gt;
&lt;h3 id="restore-databases-as-a-base-for-deployments-in-test-environments"&gt;Restore Databases as a &amp;ldquo;Base&amp;rdquo; for Deployments in Test Environments&lt;/h3&gt;
&lt;p&gt;Dependencies on objects are only checked when you run CREATE or ALTER code. These dependencies are not checked when you restore a database. It is possible to restore a database containing all sorts of invalid objects, in fact, such as views which reference tables that no longer exist.&lt;/p&gt;
&lt;p&gt;This means that you can restore databases to support dependencies, whether they are cross-database or cross-server dependencies, and you can process the restore commands in any order you like.&lt;/p&gt;
&lt;h3 id="use-synonyms-for-flexibility-across-environments"&gt;Use Synonyms for Flexibility Across Environments&lt;/h3&gt;
&lt;p&gt;Although synonyms aren&amp;rsquo;t a simple fix for a lack of deferred name resolution, they&amp;rsquo;re incredibly helpful when it comes to cross-database and cross-server dependencies.&lt;/p&gt;
&lt;p&gt;Synonyms provide a helpful level of abstraction which allows you to encapsulate any environment-specific information such as database names or linked server names in a single type of object (synonyms). One common design pattern is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create synonyms for all object dependencies outside the current database&lt;/li&gt;
&lt;li&gt;Deployments include a script which runs at the beginning of each deployment and checks that all synonyms are created properly for the target environment, and recreates them if needed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This has the benefits of making the definitions of stored procedures, views, and functions identical across databases: all objects refer to the same synonym. It also allows flexibility in environment configuration: perhaps in some environments all databases may be restored to the same SQL Server instance, while in other environments they are referred to multiple instances.&lt;/p&gt;
&lt;p&gt;I recommend following this pattern for all cross-database dependencies, even in cases where SQL Server offers deferred name resolution. Being consistent at this helps developers and database administrators working with the database understand the configuration.&lt;/p&gt;
&lt;h3 id="dynamic-sql-if-you-dare-i-do-not-dare-in-this-case"&gt;Dynamic SQL, If You Dare (I Do Not Dare in This Case)&lt;/h3&gt;
&lt;p&gt;Another option is to utilize Dynamic SQL and only create objects with external dependencies in some target environments.&lt;/p&gt;
&lt;p&gt;I am a fan of Dynamic SQL for many use cases, but I&amp;rsquo;m not generally a huge fan of it for schema definitions. This makes it hard to understand which objects are in version control.&lt;/p&gt;
&lt;h3 id="dont-use-linked-servers"&gt;Don&amp;rsquo;t Use Linked Servers&lt;/h3&gt;
&lt;p&gt;This is easier said than done when it comes to legacy codebases, but avoid linked servers whenever possible.&lt;/p&gt;
&lt;p&gt;When writing new code, always check to see if data can be managed entirely by application services and dependencies between databases can be kept to a minimum. Modern software trends generally advise on building applications with clear service boundaries and minimizing dependencies at the database level, so this usually should not be a radical request.&lt;/p&gt;
&lt;h2 id="stored-procedures-sometimes-get-deferred-name-resolution"&gt;Stored Procedures Sometimes Get Deferred Name Resolution&lt;/h2&gt;
&lt;p&gt;Stored procedures have deferred name resolution for object creation in some cases. This means that you can often create a stored procedure referencing a table that doesn&amp;rsquo;t exist yet. When the stored procedure is &lt;em&gt;executed&lt;/em&gt; for the first time, the SQL Server query processor will validate that dependencies are present.&lt;/p&gt;
&lt;h3 id="-schema-andor-object-does-not-exist"&gt;✅ Schema and/or Object Does Not Exist&lt;/h3&gt;
&lt;p&gt;For example, SQL Server can successfully create this stored procedure even though my database does not have a schema named SchemaDoesNotExist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SchemaDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Similarly, if the schema exists but no table or view exists with the given name, the stored procedure can be created as well. This code succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Stored procedures can reference temporary tables (including global temporary tables) which do not exist and be created successfully. This stored procedure can be created:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deferred name resolution isn&amp;rsquo;t only for tables and views. Deferred name resolution also works when calling other stored procedures which don&amp;rsquo;t exist. This procedure is created successfully.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcedureDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, SQL Server prints an informational message:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;The module &amp;#39;TestProcedure&amp;#39; depends on the missing object &amp;#39;dbo.ProcedureDoesNotExist&amp;#39;. The module will still be created; however, it cannot run successfully until the object exists.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can also successfully create a procedure referencing a scalar or table valued function which does not exist. Here is an example for a table valued function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableValuedFunctionDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-table-or-view-exists-but-doesnt-have-the-column-listed"&gt;❌ Table or View Exists but Doesn&amp;rsquo;t Have the Column Listed&lt;/h3&gt;
&lt;p&gt;Stored procedures cannot use deferred name resolution when they reference an object which does exist, but which does not contain a column listed. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code throws an invalid column error and the stored procedure is not created.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 207, Level 16, State 1, Procedure TestProcedure, Line 4 [Batch Start Line 2]
Invalid column name &amp;#39;SomeColumn&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-stored-procedure-in-another-database-which-is-offline"&gt;❌ Stored Procedure in Another Database Which Is Offline&lt;/h3&gt;
&lt;p&gt;The rules above also apply to references to objects in other databases on the same SQL Server instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ You can create a stored procedure referencing objects which don&amp;rsquo;t exist in another database&lt;/li&gt;
&lt;li&gt;✅ You can create a stored procedure referencing objects in a database which doesn&amp;rsquo;t exist&lt;/li&gt;
&lt;li&gt;❌ You CANNOT create a stored procedure referencing a column which does not exist in a table which does exist in another database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, if you attempt to reference an object in a database which is offline, that &lt;em&gt;sometimes&lt;/em&gt; causes a problem.&lt;/p&gt;
&lt;p&gt;To demonstrate this, first, create a database and set it offline:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get deferred name resolution if we reference a table in an offline database. This statement succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, if we try to reference a stored procedure in an offline database, our create statement fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcedureDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This returns the following error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 942, Level 14, State 4, Procedure TestProcedure, Line 3 [Batch Start Line 13]
Database &amp;#39;PutMeOffline&amp;#39; cannot be opened because it is offline.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This error does not appear if I create a stored procedure referencing a table valued function in an offline database.&lt;/p&gt;
&lt;h3 id="-object-referenced-via-a-linked-server"&gt;❌✅ Object Referenced via a Linked Server&lt;/h3&gt;
&lt;p&gt;Linked servers ruin everything.&lt;/p&gt;
&lt;p&gt;Referencing an object via a four-part name breaks deferred name resolution, for the most part.&lt;/p&gt;
&lt;p&gt;In this example, I reference a linked server which does not exist:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DatabaseDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 7202, Level 11, State 2, Procedure TestProcedure, Line 3 [Batch Start Line 0]
Could not find server &amp;#39;LinkedServerDoesNotExist&amp;#39; in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, I use a valid linked server, but reference a database which does not exist on the remote server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DERP&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;SEATTLE&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;DatabaseDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 7314, Level 16, State 1, Procedure TestProcedure, Line 3 [Batch Start Line 0]
The OLE DB provider &amp;#34;SQLNCLI11&amp;#34; for linked server &amp;#34;DERP\SEATTLE&amp;#34; does not contain the table &amp;#34;&amp;#34;DatabaseDoesNotExist&amp;#34;.&amp;#34;dbo&amp;#34;.&amp;#34;TableDoesNotExist&amp;#34;&amp;#34;. The table either does not exist or the current user does not have permissions on that table.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I get the same error if I reference a table that does not exist in a valid database across the linked server.&lt;/p&gt;
&lt;p&gt;Everything here seems to have an exception. For whatever reason, I am able to get deferred name resolution when it comes to referencing a stored procedure across a linked server. This code succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DatabaseDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcedureDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="synonyms-use-deferred-name-resolution-but-their-power-is-not-transitory"&gt;Synonyms Use Deferred Name Resolution, but Their Power Is Not Transitory&lt;/h2&gt;
&lt;p&gt;Synonyms are lightweight pointers in SQL Server. As &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/create-synonym-transact-sql"&gt;the documentation&lt;/a&gt; mentions,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The base object need not exist at synonym create time. SQL Server checks for the existence of the base object at run time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="-schema-andor-object-does-not-exist-1"&gt;✅ Schema and/or Object Does Not Exist&lt;/h3&gt;
&lt;p&gt;This synonym can be created successfully:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYNONYM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-object-referenced-via-a-linked-server-1"&gt;✅ Object Referenced via a Linked Server&lt;/h3&gt;
&lt;p&gt;I can even create a synonym referencing a linked server which does not exist:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYNONYM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DatabaseDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-object-in-another-database-which-is-offline"&gt;✅ Object in Another Database Which Is Offline&lt;/h3&gt;
&lt;p&gt;Synonyms don&amp;rsquo;t seem to have any problems with offline databases, either. I tested this with the same offline database which I created earlier with this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code to create a synonym referencing the offline database works.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: Synonyms don't support CREATE OR ALTER syntax. They do support DROP IF EXISTS.
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYNONYM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYNONYM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-using-a-synonym-doesnt-fix-a-lack-of-deferred-name-resolution-for-other-objects"&gt;❌ Using a Synonym Doesn&amp;rsquo;t Fix a Lack of Deferred Name Resolution for Other Objects&lt;/h3&gt;
&lt;p&gt;I love synonyms and it&amp;rsquo;s terrific that all of these examples work, but don&amp;rsquo;t get &lt;em&gt;too&lt;/em&gt; excited. Synonyms are not a one-stop workaround for a lack of deferred name resolution. &amp;lsquo;Run time&amp;rsquo; can apparently mean creation of an object referencing the synonym.&lt;/p&gt;
&lt;p&gt;For example, if I create a procedure that references TestSynonym as created above, the code still fails.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestProcedure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This results in the same error we saw above when referencing the table via a four-part name:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 7202, Level 11, State 2, Procedure TestProcedure, Line 3 [Batch Start Line 8]
Could not find server &amp;#39;LinkedServerDoesNotExist&amp;#39; in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Similarly, synonyms aren&amp;rsquo;t a workaround that can instantly get you deferred name resolution for other objects which lack it, such as views.&lt;/p&gt;
&lt;p&gt;Speaking of views&amp;hellip;&lt;/p&gt;
&lt;h2 id="views-do-not-get-deferred-name-resolution"&gt;Views Do Not Get Deferred Name Resolution&lt;/h2&gt;
&lt;p&gt;When you create a view in SQL Server, all dependencies need to be able to be resolved or the view will not be created successfully. This is true even if you do not create the view with SCHEMABINDING.&lt;/p&gt;
&lt;h3 id="-schema-andor-object-does-not-exist-2"&gt;❌ Schema and/or Object Does Not Exist&lt;/h3&gt;
&lt;p&gt;This script attempts to create a view referencing a table which doesn&amp;rsquo;t exist in the current database. The script fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestView&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SQL Server returns Error 208 and does not create the view.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 208, Level 16, State 1, Procedure TestView, Line 4 [Batch Start Line 0]
Invalid object name &amp;#39;dbo.TableDoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Similarly, if you try to create a view referencing a scalar function that does not exist, the script also fails. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestView&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code fails. SQL Server returns error 4121:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 4121, Level 16, State 1, Procedure TestView, Line 3 [Batch Start Line 5]
Cannot find either column &amp;#34;dbo&amp;#34; or the user-defined function or aggregate &amp;#34;dbo.SomeFunction&amp;#34;, or the name is ambiguous.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-table-or-view-exists-but-doesnt-have-the-column-listed-1"&gt;❌ Table or View Exists but Doesn&amp;rsquo;t Have the Column Listed&lt;/h3&gt;
&lt;p&gt;SQL Server must resolve not only the objects referenced, but also the columns referenced when you create a view. For example, this code attempts to use a column which doesn&amp;rsquo;t exist in the referenced table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestView&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnDoesNotExist&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code fails with error 207 and the view is not created.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 207, Level 16, State 1, Procedure TestView, Line 3 [Batch Start Line 4]
Invalid column name &amp;#39;ColumnDoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-object-in-another-database-which-is-offline-1"&gt;❌ Object in Another Database Which Is Offline&lt;/h3&gt;
&lt;p&gt;You cannot create a view referencing an object in an offline database, as attempted in this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestView&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 942:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 942, Level 14, State 4, Procedure TestView, Line 3 [Batch Start Line 5]
Database &amp;#39;PutMeOffline&amp;#39; cannot be opened because it is offline.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-object-referenced-via-a-linked-server-distributed-view"&gt;❌ Object Referenced via a Linked Server (Distributed View)&lt;/h3&gt;
&lt;p&gt;The above rules hold true for tables in other databases referenced using three-part naming, as well as tables referenced across linked servers using four-part naming. SQL Server must validate that the objects and columns referenced exist, or it cannot create the view.&lt;/p&gt;
&lt;p&gt;Here is an example for a linked server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestView&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeLinkedServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 208:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 208, Level 16, State 1, Procedure TestView, Line 4 [Batch Start Line 0]
Invalid object name &amp;#39;SomeLinkedServer.dbo.TableDoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-synonym-references-object-which-doesnt-exist"&gt;❌ Synonym References Object Which Doesn&amp;rsquo;t Exist&lt;/h3&gt;
&lt;p&gt;As mentioned above, synonyms can be created referencing objects which don&amp;rsquo;t exist, but this isn&amp;rsquo;t a simple workaround for objects which lack deferred name resolution. This code successfully creates a synonym, dbo.TestSynonym, which references a table which doesn&amp;rsquo;t exist. However, the code to create the view which references the synonym fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYNONYM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYNONYM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VIEW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestView&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestSynonym&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SQL Server returns error 5313 in this case:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 5313, Level 16, State 1, Procedure TestView, Line 4 [Batch Start Line 5]
Synonym &amp;#39;dbo.TestSynonym&amp;#39; refers to an invalid object.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-how-circular-views-come-into-existence"&gt;🔄 How Circular Views Come into Existence&lt;/h3&gt;
&lt;p&gt;It is possible to have circular references between views in SQL Server. In this case, 2 or more views are mutually dependent upon one another. This typically happens by a process like the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;View dbo.V1 is created referencing only tables in the database&lt;/li&gt;
&lt;li&gt;View dbo.V2 is created with a reference to dbo.V1&lt;/li&gt;
&lt;li&gt;View dbo.V1 is edited and a dependency to dbo.V2 is added&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SQL Server allows this progression of changes to be deployed, but this results in a situation where views dbo.V1 and dbo.V2 cannot be successfully created in an empty database using their full definitions.&lt;/p&gt;
&lt;h2 id="function-behavior-varies-by-type"&gt;Function Behavior Varies by Type&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m looking at scalar, inline (single statement) table valued functions, and multi-statement table valued functions separately because some get deferred name resolution and some don&amp;rsquo;t.&lt;/p&gt;
&lt;h3 id="scalar-functions"&gt;Scalar Functions&lt;/h3&gt;
&lt;h4 id="-schema-andor-object-does-not-exist-3"&gt;✅ Schema and/or Object Does Not Exist&lt;/h4&gt;
&lt;p&gt;Scalar functions can get deferred name resolution. The following code referencing a table which does not exist succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestScalarFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You might wonder if a call to this function works, since 1 is returned no matter what happens within the function. Let&amp;rsquo;s test that out with the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestScalarFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 208:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 208, Level 16, State 1, Line 11
Invalid object name &amp;#39;dbo.TableDoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-table-or-view-exists-but-doesnt-have-the-column-listed-2"&gt;❌ Table or View Exists but Doesn&amp;rsquo;t Have the Column Listed&lt;/h4&gt;
&lt;p&gt;Just like with stored procedures, if you create a scalar function referencing a table or view which exists, SQL Server will check the columns you specify and require that they are valid. This code to create dbo.TestScalarFunction fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestScalarFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SQL Server returns error 207 and does not create the function.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 207, Level 16, State 1, Procedure TestScalarFunction, Line 6 [Batch Start Line 4]
Invalid column name &amp;#39;DoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-object-in-another-database-which-is-offline-2"&gt;✅ Object in Another Database Which Is Offline&lt;/h4&gt;
&lt;p&gt;Like stored procedures scalar functions which reference tables in offline databases can be created successfully. This code succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestScalarFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Stored procedures have a gotcha where they fail if they reference another stored procedure in an offline database. I don&amp;rsquo;t believe that scalar functions can call stored procedures 🤔, so there is no issue here.&lt;/p&gt;
&lt;p&gt;I did test a scalar function which calls a scalar function in an offline database. This code succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestScalarFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="-object-referenced-via-a-linked-server-2"&gt;❌ Object Referenced via a Linked Server&lt;/h4&gt;
&lt;p&gt;Creating a scalar function referencing an object across a linked server seems like a recipe for extreme pain, but SQL Server does allow this.&lt;/p&gt;
&lt;p&gt;However, to create the function SQL Server will need to cross the linked server and validate that the object, and any columns referenced in it, exist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestScalarFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="inline-table-valued-functions-tvfs"&gt;Inline Table Valued Functions (TVFs)&lt;/h3&gt;
&lt;p&gt;Unlike scalar functions, inline TVFs do NOT get deferred name resolution.&lt;/p&gt;
&lt;h4 id="-schema-andor-object-does-not-exist-4"&gt;❌ Schema and/or Object Does Not Exist&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestInlineTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 208, Level 16, State 1, Procedure TestInlineTableValuedFunction, Line 4 [Batch Start Line 0]
Invalid object name &amp;#39;dbo.TableDoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-table-or-view-exists-but-doesnt-have-the-column-listed-3"&gt;❌ Table or View Exists but Doesn&amp;rsquo;t Have the Column Listed&lt;/h4&gt;
&lt;p&gt;If you reference a table which exists in an inline TVF, you can only reference columns which exist. Here is our demo code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestInlineTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 207:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 207, Level 16, State 1, Procedure TestInlineTableValuedFunction, Line 4 [Batch Start Line 4]
Invalid column name &amp;#39;DoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-object-in-another-database-which-is-offline-3"&gt;❌ Object in Another Database Which Is Offline&lt;/h4&gt;
&lt;p&gt;Inline TVFs cannot reference objects in offline databases. Here is our example code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestInlineTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with the error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 942, Level 14, State 4, Procedure TestInlineTableValuedFunction, Line 4 [Batch Start Line 5]
Database &amp;#39;PutMeOffline&amp;#39; cannot be opened because it is offline.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-object-referenced-via-a-linked-server-3"&gt;❌ Object Referenced via a Linked Server&lt;/h4&gt;
&lt;p&gt;If you reference a linked server in your inline TVF definition, SQL Server will need to successfully access the linked server and validate that the object and any columns referenced exists. Here is our demo code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestInlineTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code fails with error 7202:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 7202, Level 11, State 2, Procedure TestInlineTableValuedFunction, Line 4 [Batch Start Line 0]
Could not find server &amp;#39;LinkedServerDoesNotExist&amp;#39; in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="multi-statement-table-valued-functions-tvfs"&gt;Multi-Statement Table Valued Functions (TVFs)&lt;/h3&gt;
&lt;p&gt;Multi-statement table valued functions can get deferred name resolution sometimes. In my testing, I found the behavior of multi-statement TVFs to match the behavior of stored procedures regarding deferred name resolution.&lt;/p&gt;
&lt;h4 id="-schema-andor-object-does-not-exist-5"&gt;✅ Schema and/or Object Does Not Exist&lt;/h4&gt;
&lt;p&gt;This create statement for a multi-statement table valued function succeeds, although it references a table which does not exist:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestMultiStatementTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="-table-or-view-exists-but-doesnt-have-the-column-listed-4"&gt;❌ Table or View Exists but Doesn&amp;rsquo;t Have the Column Listed&lt;/h4&gt;
&lt;p&gt;Consistent with what we&amp;rsquo;ve seen in other examples, if an object exists then any columns listed for the object must exist as well. Here is our example code to test this in a multi-statement table valued function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestMultiStatementTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 207:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 207, Level 16, State 1, Procedure TestMultiStatementTableValuedFunction, Line 4 [Batch Start Line 4]
Invalid column name &amp;#39;DoesNotExist&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-object-in-another-database-which-is-offline-4"&gt;❌ Object in Another Database Which Is Offline&lt;/h4&gt;
&lt;p&gt;Like stored procedures, I found that multi-statement TVFs can reference tables and views in offline databases. This code executes successfully:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestMultiStatementTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, if I add a statement which calls a stored procedure in the offline database, the code fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PutMeOffline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestMultiStatementTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcedureDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PutMeOffline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 942:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 942, Level 14, State 4, Procedure TestMultiStatementTableValuedFunction, Line 4 [Batch Start Line 19]
Database &amp;#39;PutMeOffline&amp;#39; cannot be opened because it is offline.&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="-object-referenced-via-a-linked-server-4"&gt;❌✅ Object Referenced via a Linked Server&lt;/h4&gt;
&lt;p&gt;Finally, if you attempt to create a multi-statement TVF which references a table or view via a linked server, as with our other test cases SQL Server must access the linked server and validate that the object and any referenced columns exist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestMultiStatementTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fails with error 7202:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Msg 7202, Level 11, State 2, Procedure TestMultiStatementTableValuedFunction, Line 4 [Batch Start Line 0]
Could not find server &amp;#39;LinkedServerDoesNotExist&amp;#39; in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, as with stored procedures, multi-statement TVFs might execute a procedure across a linked server. Oddly enough, this code succeeds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestMultiStatementTableValuedFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doggo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedServerDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Something&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Learn Azure SQL with One Free Learning Path</title><link>https://kendralittle.com/2021/10/14/learn-azure-sql-free-learning-path/</link><pubDate>Thu, 14 Oct 2021 09:03:05 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/10/14/learn-azure-sql-free-learning-path/</guid><description>&lt;p&gt;Have you been meaning to learn about SQL Server in the Azure cloud, but never seem to get around to it? It&amp;rsquo;s easy to be overwhelmed and not know where to begin.&lt;/p&gt;
&lt;p&gt;I recommend you start with the &lt;a href="https://docs.microsoft.com/en-us/learn/paths/azure-sql-fundamentals/"&gt;Azure SQL Fundamentals Learning Path&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I stepped through this training this week and WOW, this is an incredibly high quality free course, complete with hands-on exercises in an online sandbox. I wish I&amp;rsquo;d done this sooner!&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/george-hiles-T6MSs7ZbBQ4-unsplash.jpg"
alt="A photograph of a path between two cliffs/dunes with databases drawn along the path." width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="top-notch-quality"&gt;Top-Notch Quality&lt;/h2&gt;
&lt;p&gt;I say this is a high quality training because the course explains both general concepts and is also full of specific, useful, current details about Azure SQL.&lt;/p&gt;
&lt;p&gt;Having written training modules myself, I know how difficult this is to maintain, especially given the rapid rate of evolution of cloud technologies. This Learning Path is clearly frequently updated and kept current by a team with very deep knowledge of Azure SQL.&lt;/p&gt;
&lt;h2 id="why-learn-azure-sql"&gt;Why Learn Azure SQL?&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s increasingly useful for database administrators and developers to understand PaaS (Platform as a Service) and IaaS (Infrastructure as a Service) cloud offerings and how these compare to installing and managing databases on-prem.&lt;/p&gt;
&lt;p&gt;Even if your current job doesn&amp;rsquo;t work with databases in the cloud, learning the fundamentals of Azure SQL is likely going to help you out when it comes to seeking a promotion or landing a new job.&lt;/p&gt;
&lt;p&gt;Note that I say &lt;em&gt;fundamentals&lt;/em&gt; here. Not everyone needs to become an expert, but understanding the fundamentals is starting to become &lt;a href="https://en.wikipedia.org/wiki/Table_stakes"&gt;table stakes&lt;/a&gt; for database jobs.&lt;/p&gt;
&lt;h2 id="what-does-azure-sql-mean"&gt;What Does &amp;lsquo;Azure SQL&amp;rsquo; Mean?&lt;/h2&gt;
&lt;p&gt;&amp;lsquo;Azure SQL&amp;rsquo; is a term that encompasses three types of offerings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure SQL Database: a PaaS offering (database as a service)&lt;/li&gt;
&lt;li&gt;Azure SQL Managed Instance: a PaaS offering (a SQL Server instance as a service)&lt;/li&gt;
&lt;li&gt;SQL Server running on Azure Virtual Machines: an IaaS offering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The course largely focuses on the details of Azure SQL Database and Azure SQL Managed Instances. This makes sense as SQL Server running on Azure Virtual Machines is broadly similar to running SQL Server on Virtual Machines in any environment.&lt;/p&gt;
&lt;p&gt;Sandbox examples typically leverage Azure SQL Database in the course, which I suspect is because these databases spin up in a matter of minutes, while Azure SQL Managed Instances can still take up to six hours to spin up. I found this to be sufficient for learning fundamentals. The course provides a lot of details and screenshots about Azure SQL Managed Instances which I found very helpful.&lt;/p&gt;
&lt;h2 id="how-to-tackle-the-learning-path"&gt;How to Tackle the Learning Path&lt;/h2&gt;
&lt;p&gt;I recommend following a strategy related to your level of experience and knowledge about SQL Server.&lt;/p&gt;
&lt;h3 id="sql-server-beginners"&gt;SQL Server Beginners&lt;/h3&gt;
&lt;p&gt;If you are more of a generalist or are newer to SQL Server, this course can still be great for you but make sure not to get distracted by the details. There are &lt;em&gt;tons&lt;/em&gt; of facts in this course which you could dig into and research for hours.&lt;/p&gt;
&lt;p&gt;I recommend timeboxing your learning and focusing on the big picture: you&amp;rsquo;ll get a ton of value out of the course. You can always come back and dig into specific modules more afterward.&lt;/p&gt;
&lt;h3 id="sql-server-experts"&gt;SQL Server Experts&lt;/h3&gt;
&lt;p&gt;If you have a lot of experience with SQL Server, I suspect that you&amp;rsquo;ll find the course answers a lot of the questions you might have about performance, scalability, high availability, and disaster recovery. I encourage you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dig into the command line examples, even if you&amp;rsquo;re normally one to use a graphic portal&lt;/li&gt;
&lt;li&gt;Go off-road and explore more around the given examples&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-the-sandbox-is-particularly-cool"&gt;Why the &amp;lsquo;Sandbox&amp;rsquo; Is Particularly Cool&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Azure-Fundamentals-Learning-Path-Sandbox.png"
alt="Screenshot of an exercise after launching the sandbox in the Azure Fundamentals Learning Path" width="700"&gt;&lt;figcaption&gt;
&lt;p&gt;An exercise after I have launched the sandbox&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I really like how the hands-on examples are implemented in these Learning Paths. &amp;lsquo;Sandboxes&amp;rsquo; are integrated into the course itself. When you launch the sandbox it connects to your Azure Account, but it does something really cool: it creates a special Concierge folder for you which utilizes a Concierge subscription. Your Sandbox runs real resources in Azure, it is not a simulation.&lt;/p&gt;
&lt;p&gt;I like this for multiple reasons. First, it was easy for me to get working. Second, it&amp;rsquo;s a simple way for users to not have to worry about costs. Finally, it segments off your learning away from any &amp;ldquo;normal&amp;rdquo; Azure usage you might have. The Sandbox environments are regularly cleaned up, so you don&amp;rsquo;t need to worry about forgetting to run a clean-up script if something comes up and you get pulled away from an exercise before you complete it.&lt;/p&gt;
&lt;h2 id="links-to-get-going"&gt;Links to Get Going&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/learn/paths/azure-sql-fundamentals/"&gt;Azure SQL Fundamentals Learning Path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/learn/browse/?resource_type=learning%20path&amp;amp;terms=sql"&gt;All Learning Paths related to the keyword &amp;lsquo;sql&amp;rsquo;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>New Tricks I Learned from the Azure Data Studio Code Editor Tutorial</title><link>https://kendralittle.com/2021/10/07/trying-out-azure-data-studio-quickstart/</link><pubDate>Thu, 07 Oct 2021 15:00:03 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/10/07/trying-out-azure-data-studio-quickstart/</guid><description>&lt;p&gt;Today I walked through the &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/quickstart-sql-database"&gt;Use Azure Data Studio to connect and query Azure SQL database&lt;/a&gt; Quickstart. This Quickstart is solid and is great for someone new to Azure Data Studio.&lt;/p&gt;
&lt;p&gt;At the end of the Quickstart it suggested I try the &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/tutorial-sql-editor"&gt;Tutorial: Use the Transact-SQL editor to create database objects - Azure Data Studio&lt;/a&gt;. The tutorial taught me a couple of things that I&amp;rsquo;ve not noticed about Azure Data Studio, even though I&amp;rsquo;ve used it for a couple of years.&lt;/p&gt;
&lt;h2 id="built-in-snippets-are-quite-useful"&gt;Built-In Snippets Are Quite Useful&lt;/h2&gt;
&lt;p&gt;I had no idea that Azure Data Studio had built in snippet functionality. And I admit that as soon as I skimmed the tutorial and saw there were snippets, I &lt;em&gt;tried to use them the wrong way&lt;/em&gt;. I assumed that I&amp;rsquo;d open the Command Palette to insert a snippet. Nope!&lt;/p&gt;
&lt;p&gt;To access snippets, simply type &lt;strong&gt;sql&lt;/strong&gt; into the query editor itself. This will initialize a drop-down list which you can arrow through:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/AvNWbj9ZTKBRSiCo18/source.gif"
alt="Animated GIF showing how to access SQL snippets in Azure Data Studio by typing &amp;#39;sql&amp;#39; in the query editor" width="854"&gt;
&lt;/figure&gt;
&lt;h2 id="you-can-create-your-own-snippets"&gt;You Can Create Your Own Snippets&lt;/h2&gt;
&lt;p&gt;There are built-in snippets for lots of things: data definition changes like creating indexes or adding columns, data modification tasks like inserting or deleting rows, or management tasks like listing databases or finding space used.&lt;/p&gt;
&lt;p&gt;But you might want to &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/code-snippets"&gt;create your own snippets&lt;/a&gt;, too.&lt;/p&gt;
&lt;h2 id="peek-definition-functionality-exists-too"&gt;&amp;lsquo;Peek Definition&amp;rsquo; Functionality Exists, Too&lt;/h2&gt;
&lt;p&gt;I also hadn&amp;rsquo;t realized that Azure Data Studio supports &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/code-snippets"&gt;Peek Definition&lt;/a&gt; functionality natively. The example given in a tutorial of peeking at a table&amp;rsquo;s definition when writing an insert statement is right on.&lt;/p&gt;
&lt;h2 id="bonus-dragging-the-columns-folder-into-a-query-edit-works-just-like-in-ssms"&gt;Bonus: Dragging the Columns Folder into a Query Edit Works Just Like in SSMS&lt;/h2&gt;
&lt;p&gt;Stepping through the Peek Definition example made me wonder if one of my favorite lazy hacks from SQL Server Management Studio works in Azure Data Studio. Sure enough, it does! You can write out the list of columns in a table in your query editor by dragging the column folder for the table into the query editor window:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/lnMSgx15UDyy0VwVRP/source.gif"
alt="Animated GIF showing how to drag the columns folder from a table into the query editor in Azure Data Studio" width="854"&gt;
&lt;/figure&gt;
&lt;h2 id="azure-data-studio-isnt-just-for-azure-sql"&gt;Azure Data Studio Isn&amp;rsquo;t Just for Azure SQL&lt;/h2&gt;
&lt;p&gt;Don&amp;rsquo;t let the name fool ya. Azure Data Studio works for &lt;strong&gt;both&lt;/strong&gt; Azure SQL and on-prem SQL Server installations.&lt;/p&gt;</description></item><item><title>Trying Out the Azure SQL Database Quickstart</title><link>https://kendralittle.com/2021/10/04/azure-sql-database-quickstart/</link><pubDate>Mon, 04 Oct 2021 11:19:52 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/10/04/azure-sql-database-quickstart/</guid><description>&lt;p&gt;I&amp;rsquo;m working through a series of tutorials and learning paths for Azure SQL and sharing bite-sized reviews.&lt;/p&gt;
&lt;p&gt;In this first walkthrough, I&amp;rsquo;m stepping through the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal"&gt;Create a Single Database&lt;/a&gt; tutorial.&lt;/p&gt;
&lt;h2 id="a-nice-feature-choose-if-you-wish-to-work-in-the-graphic-portal-or-in-a-command-line"&gt;A Nice Feature: Choose If You Wish to Work in the Graphic Portal or in a Command Line&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s really nice that the Quickstart offers multiple options to learn.&lt;/p&gt;
&lt;p&gt;You can get instructions to walk through steps in the portal if you prefer, or you get three different options for working in a command line. Switching between these is as simple as clicking on tab headings in the Quickstart:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/azure-sql-quickstart-options.jpg"
alt="screenshot of the tutorial showing options for Azure Portal, Azure CLI, Azure CLI (sql up), PowerShell" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;It&amp;rsquo;s convenient that you can run the Azure Cloud Shell in the same browser page as the documentation to try out the example. It&amp;rsquo;s nice to not need to open a separate terminal and toggle between windows.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/azure-sql-quickstart-creating-a-database.jpg"
alt="screenshot of using the Azure Cloud Shell in the browser along with the tutorial." width="800"&gt;
&lt;/figure&gt;
&lt;h2 id="whats-the-difference-between-the-azure-cli-azure-cli-sql-up-and-powershell-examples"&gt;What&amp;rsquo;s the Difference Between the Azure CLI, Azure CLI (sql up), and PowerShell Examples?&lt;/h2&gt;
&lt;p&gt;I was immediately a bit puzzled as to why I have &lt;em&gt;three&lt;/em&gt; command line options. This is a lot of choices!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the three command line options compare and why you might choose one over another:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left"&gt;Option&lt;/th&gt;
&lt;th style="text-align: left"&gt;Description&lt;/th&gt;
&lt;th style="text-align: left"&gt;Why you would use it&lt;/th&gt;
&lt;th style="text-align: left"&gt;Type of Azure SQL Database created in Quickstart&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;Azure CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;This example utilizes a variety of commands that are part of the Azure CLI (command line interface). This example is written for the &lt;a href="https://docs.microsoft.com/en-us/learn/modules/bash-introduction/1-what-is-bash"&gt;Bash&lt;/a&gt; shell.&lt;/td&gt;
&lt;td style="text-align: left"&gt;You want more granular control over the database creation process. You are comfortable with or wish to learn Bash syntax.&lt;/td&gt;
&lt;td style="text-align: left"&gt;Serverless, Gen 5, 2 vCores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;Azure CLI (sql up)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;This example utilizes the Azure CLI and the example is written in the Bash shell. This example is much shorter, as it leverages the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/sql#az_sql_up"&gt;az sql up&lt;/a&gt; command, which can create the resource group, logical server, and database in a single command.&lt;/td&gt;
&lt;td style="text-align: left"&gt;You want a single Bash command to quickly create an Azure SQL Database.&lt;/td&gt;
&lt;td style="text-align: left"&gt;Provisioned, Gen 5, 2 vCores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;PowerShell&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;This example utilizes the Azure CLI but is written with &lt;a href="https://docs.microsoft.com/en-us/powershell/scripting/overview"&gt;PowerShell&lt;/a&gt; cmdlets and utilizes PowerShell syntax (instead of Bash commands and bash syntax).&lt;/td&gt;
&lt;td style="text-align: left"&gt;You want more granular control over the database creation process. You are comfortable with or wish to learn PowerShell.&lt;/td&gt;
&lt;td style="text-align: left"&gt;Serverless, Gen 5, 2 vCores&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Note that &lt;a href="https://docs.microsoft.com/en-us/cli/azure/get-started-with-azure-cli"&gt;one line examples of the Azure CLI&lt;/a&gt; will work in any shell.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-powershell-example-worked-perfectly"&gt;The PowerShell Example Worked Perfectly&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve created Azure SQL Databases in the Portal quite a few times in the past. I have less experience using the command line options to create and manage Azure SQL Databases, so I wanted to try those out and learn more.&lt;/p&gt;
&lt;p&gt;First I stepped through the PowerShell example using the in-browser Azure Cloud Shell. That worked very well.&lt;/p&gt;
&lt;p&gt;At one point I needed to work on something else in the middle of trying the example. I found I needed to restart the browser shell, and it cleared out the parameters I was using. I simply restarted the example from the beginning and it all worked perfectly a second time through, even though I&amp;rsquo;d stopped mid-way.&lt;/p&gt;
&lt;h2 id="the-sql-up-example-threw-an-error"&gt;The &amp;ldquo;sql up&amp;rdquo; Example Threw an Error&lt;/h2&gt;
&lt;p&gt;Next I stepped through the Azure CLI (sql up) example. In the PowerShell example you could simply copy and past all the commands without modifying them, with the exception of needing to specify your own IP address for a firewall exception. That didn&amp;rsquo;t work this time. I ran the command as given:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az sql up &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --resource-group &lt;span class="nv"&gt;$resourceGroupName&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --location &lt;span class="nv"&gt;$location&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --server-name &lt;span class="nv"&gt;$serverName&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --database-name mySampleDatabase &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --admin-user &lt;span class="nv"&gt;$adminlogin&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --admin-password &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This resulted in an error:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-error" data-lang="error"&gt;argument --resource-group/-g: expected one argument&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I looked at what I&amp;rsquo;d run and realized that I hadn&amp;rsquo;t ever initialized the variables &lt;code&gt;$resourceGroupName&lt;/code&gt;, &lt;code&gt;$location&lt;/code&gt;, &lt;code&gt;$serverName&lt;/code&gt;, &lt;code&gt;$adminlogin&lt;/code&gt;, and &lt;code&gt;$password&lt;/code&gt;. I needed to either add a block of text assigning those values, remove the variables altogether (sql up will create defaults), or use literal values.&lt;/p&gt;
&lt;p&gt;I changed my command to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az sql up &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --resource-group myResourceGroup &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --location eastus &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --server-name server-&lt;span class="nv"&gt;$RANDOM&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --database-name mySampleDatabase &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --admin-user azureuser &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --admin-password Azure1234567!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This worked, and created a resource group, logical server, and Azure SQL Database all in one step!&lt;/p&gt;
&lt;p&gt;This was pretty fun to see this happen all in one command.&lt;/p&gt;
&lt;h2 id="highlights-and-lowlights"&gt;Highlights and Lowlights&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a lot to like about the Quickstart experience with Azure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;One thing I&amp;rsquo;ve noticed over the years is that Microsoft has made it incredibly easy to configure initial firewall rules when setting up an Azure SQL Database. Configuring the firewall is part of the examples. If you are using the Azure Portal, SQL Server Management Studio, or Azure Data Studio to query an Azure SQL Database, they will attempt to help you configure firewall rules if needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another thing I noticed is that the Quickstarts create a resource group at the beginning of the example. At the end of the example, they show you how to clean up everything you created by deleting the resource group. That&amp;rsquo;s a nice, simple way to help the user not need to manually delete items or risk leaving things around.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there&amp;rsquo;s a lowlight, it&amp;rsquo;s simply that it can take a bit of time for things to spin up.&lt;/p&gt;
&lt;p&gt;This is totally reasonable: when you step through the Quickstart, you are creating real resources in Azure. There&amp;rsquo;s a fair amount going on in the background.&lt;/p&gt;
&lt;p&gt;However, you might be waiting for a minute or two at different points along the way. One nice thing about having the Azure Cloud Shell in the browser with the documentation is that you can read the documentation on the same page while you wait, and just keep an eye out to see when your command completes.&lt;/p&gt;</description></item><item><title>Tutorial: Create a Disposable SQL Server Database Container in an Azure DevOps Pipeline With Spawn</title><link>https://kendralittle.com/2021/07/13/creating-a-disposable-sql-server-database-container-in-azure-devops-pipelines-with-spawn/</link><pubDate>Tue, 13 Jul 2021 11:13:31 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/07/13/creating-a-disposable-sql-server-database-container-in-azure-devops-pipelines-with-spawn/</guid><description>&lt;p&gt;&lt;em&gt;This post is part of &lt;a href="https://www.centinosystems.com/blog/sql/t-sql-tuesday-140-what-have-you-been-up-to-with-containers/"&gt;TSQLTuesday #140, &amp;ldquo;What have you been up to with containers?&amp;rdquo;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Disposable databases are indispensable for software developers, both for initial development work and in automation pipelines. Containers pair exceptionally well with temporary databases and provide a lightweight mechanism to spin up an environment on demand.&lt;/p&gt;
&lt;p&gt;In this post, I share why we need disposable databases, use cases for disposable databases in automated workflows, and a tutorial to create an Azure DevOps pipeline to spin up an AdventureWorks2019 sample data container on demand using &lt;a href="https://spawn.cc/"&gt;Spawn&lt;/a&gt;. Spawn has a free tier which you can try out anytime.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/spawn.png"
alt="Spawn logo" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="why-we-need-disposable-databases"&gt;Why We Need Disposable Databases&lt;/h2&gt;
&lt;p&gt;There are two main reasons why we need disposable databases for software development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing database changes requires a realistic dataset.&lt;/strong&gt; Schema isn&amp;rsquo;t enough! Will that unique index create successfully in production? Can you add a non-nullable column to that table without a default value? How will this query perform? We need realistic datasets for these scenarios and more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Databases generally don&amp;rsquo;t have good ways to &amp;ldquo;reset&amp;rdquo; after you make changes&lt;/strong&gt;. I say &amp;ldquo;good&amp;rdquo; here because some techniques do exist. SQL Server, for example, has a database snapshot feature. One can create a database snapshot at a point in time, make some changes, and later revert to that snapshot. But this feature doesn&amp;rsquo;t scale for software development. Database snapshots aren&amp;rsquo;t portable: they are tightly coupled with the source database. Database snapshots are read-only for a point in time: they are not writeable. The database snapshot feature is also cumbersome to implement and wasn&amp;rsquo;t designed with automation in mind.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without disposable databases, it is much harder to do quality testing of changes. It&amp;rsquo;s also much harder to validate deployments when &lt;a href="https://www.red-gate.com/simple-talk/blogs/reordering-deployments-in-database-devops/"&gt;reordering changes in release pipelines&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-containerized-service-for-ephemeral-database-containers"&gt;A Containerized Service for Ephemeral Database Containers&lt;/h2&gt;
&lt;p&gt;Redgate&amp;rsquo;s Foundry team created &lt;a href="https://spawn.cc/"&gt;Spawn&lt;/a&gt; to explore how a containerized service can solve the problems above. The Spawn cloud service lets users:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create &lt;a href="https://docs.spawn.cc/how-tos/dataimage"&gt;data images&lt;/a&gt;. Your image can be empty, you can create it from scripts, or you can create it from &lt;a href="https://docs.spawn.cc/data-image-configuration/backup"&gt;database backups&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create &lt;a href="https://docs.spawn.cc/how-tos/datacontainer"&gt;data containers&lt;/a&gt; from images. These containers can be quickly created, used, and then removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are just the basics. There is a lot more functionality available, including resetting containers and graduating containers to new images.&lt;/p&gt;
&lt;h2 id="two-use-cases-for-disposable-databases-in-pipelines"&gt;Two Use Cases for Disposable Databases in Pipelines&lt;/h2&gt;
&lt;h3 id="continuous-integration-builds"&gt;Continuous Integration Builds&lt;/h3&gt;
&lt;p&gt;When your repository contains database code, it&amp;rsquo;s essential to ensure the code is valid, just like any other code. Disposable databases allow you to automate code validation for your database code whenever someone commits or merges changes into a code branch. Continuous Integration can call a pipeline or action which will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a data container including the database&lt;/li&gt;
&lt;li&gt;Deploy changes from the repo to the database&lt;/li&gt;
&lt;li&gt;Fail the action or pipeline if the code doesn&amp;rsquo;t deploy successfully&lt;/li&gt;
&lt;li&gt;Clean up the data container at the end of the job&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="pull-requests"&gt;Pull Requests&lt;/h3&gt;
&lt;p&gt;One example of using a disposable database in an automation pipeline is in a Pull Request (PR) workflow when using Git. In this workflow, a developer will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a local Git branch&lt;/li&gt;
&lt;li&gt;Make database changes locally to their environment (maybe a disposable database which they spin up just for the branch)&lt;/li&gt;
&lt;li&gt;Save and commit their changes to Git locally using the team&amp;rsquo;s preferred tooling for the project&lt;/li&gt;
&lt;li&gt;Push their branch up to the central repo&lt;/li&gt;
&lt;li&gt;Create a Pull Request on the central repo to merge the code into a shared branch (commonly &amp;ldquo;main&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is often an option for automation to kick off at this point to validate the code in your branch. Effective automation will save work for the folks reviewing your Pull Request while enabling them to do high quality review of your changes. If you have a database cloning solution, this automation can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a data container including the database&lt;/li&gt;
&lt;li&gt;Deploy changes from the repo to the database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Optionally, you can keep the database around for the reviewers to inspect as part of the PR review. Many teams prefer to build an entire environment (database, application components, etc.) for use in PR reviews.&lt;/p&gt;
&lt;h2 id="prerequisites-to-follow-this-tutorial"&gt;Prerequisites to Follow This Tutorial&lt;/h2&gt;
&lt;p&gt;All of the accounts, services, and tools used in this tutorial offer free tiers. To follow along, you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://github.com/"&gt;GitHub account&lt;/a&gt; to connect to Spawn.&lt;/li&gt;
&lt;li&gt;An Azure DevOps project - the &lt;a href="https://azure.microsoft.com/en-us/pricing/details/devops/azure-devops-services/"&gt;free tier&lt;/a&gt; works fine. The project repo can be empty (no database code is required).&lt;/li&gt;
&lt;li&gt;To &lt;a href="https://docs.spawn.cc/getting-started/installation"&gt;install the Spawn command line&lt;/a&gt; on a computer. This has a few simple steps: log in to the Spawn web app with GitHub, download the Spawn command line executable to a local folder, add the folder to your path, and then run &lt;code&gt;spawnctl auth&lt;/code&gt; in a terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: We won&amp;rsquo;t deploy database code to the data container in this tutorial itself, but we&amp;rsquo;ll set the foundation to do that in a future tutorial.&lt;/p&gt;
&lt;h2 id="create-an-azure-devops-pipeline"&gt;Create an Azure DevOps Pipeline&lt;/h2&gt;
&lt;p&gt;In this example, I am working with a newly created Azure DevOps project. I&amp;rsquo;ve initialized the default Git repo with a readme, but I haven&amp;rsquo;t added any code.&lt;/p&gt;
&lt;p&gt;First, click &lt;strong&gt;Pipelines&lt;/strong&gt; in the left menu bar, then click &lt;strong&gt;New pipeline&lt;/strong&gt; at the top right.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsNewPipeline.png"
alt="Azure DevOps pipelines screen with the New pipeline button" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;At the &lt;strong&gt;Where is your code?&lt;/strong&gt; prompt, click &lt;strong&gt;Azure Repos Git&lt;/strong&gt;. This is a YAML pipeline. (You could also do this process with code stored in Bitbucket Cloud or GitHub.)
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsRepoType.png"
alt="Azure DevOps prompt to select repo location" width="900"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;At the &lt;strong&gt;Select a repository&lt;/strong&gt; prompt, click on the name of the repo.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsRepoName.png"
alt="Azure DevOps prompt to select a repository" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Troubleshooting&lt;/em&gt;: If you do not see a repo name here and this is a new Azure DevOps project, click on &lt;strong&gt;Repos&lt;/strong&gt; in the left bar. If it says &amp;ldquo;[YourRepoName] is empty. Add some code!&amp;rdquo; at the top, one way to get it working fast is to scroll to the bottom of the page and click &lt;strong&gt;Initialize&lt;/strong&gt; with the &amp;ldquo;Add a README&amp;rdquo; option ticked.&lt;/p&gt;
&lt;p&gt;At the &lt;strong&gt;Configure your pipeline&lt;/strong&gt; prompt, select &lt;strong&gt;Starter pipeline&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsStarterPipeline.png"
alt="Azure DevOps prompt to create a starter pipeline or choose existing YAML file" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;This should bring you to the &lt;strong&gt;Review your pipeline YAML&lt;/strong&gt; screen, with simple starter code in a YAML pipeline.&lt;/p&gt;
&lt;h3 id="add-yaml-to-the-pipeline-to-create-a-spawn-data-container"&gt;Add YAML to the Pipeline to Create a Spawn Data Container&lt;/h3&gt;
&lt;p&gt;Our next step is to replace that starter pipeline code with the following YAML. This YAML will&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use an Azure-hosted agent running ubuntu-latest&lt;/li&gt;
&lt;li&gt;Download and install the Spawn command line (spawnctl) to the agent&lt;/li&gt;
&lt;li&gt;Create a data container based on the image name specified in a variable named $(DATA_IMAGE_NAME) with a lifetime of 20 minutes&lt;/li&gt;
&lt;li&gt;Authenticate to Spawn by using an access token stored in a variable named $(SPAWNCTL_ACCESS_TOKEN)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="l"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;vmImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# variable: $(SPAWNCTL_ACCESS_TOKEN) - https://docs.spawn.cc/commands/spawnctl-accesstoken-get&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Variable: $(DATA_IMAGE_NAME) - to test quickly use a public image https://docs.spawn.cc/other/public-data-images &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; echo &amp;#34;Downloading and installing spawnctl...&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; curl -sL https://run.spawn.cc/install | sh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Install spawnctl&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; set -e
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; export PATH=$PATH:$HOME/.spawnctl/bin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; dataContainer=$(spawnctl create data-container --image $(DATA_IMAGE_NAME) --lifetime 20m -q )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; echo &amp;#34;##vso[task.setvariable variable=dataContainerName]$dataContainer&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; dataContainerJson=$(spawnctl get data-container $dataContainer -o json)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; port=$(echo $dataContainerJson | jq -r .port)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; host=$(echo $dataContainerJson | jq -r .host)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; user=$(echo $dataContainerJson | jq -r .user)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; password=$(echo $dataContainerJson | jq -r .password)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;spawn a database&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;SPAWNCTL_ACCESS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;$(SPAWNCTL_ACCESS_TOKEN)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="add-variables-to-your-pipeline"&gt;Add Variables to Your Pipeline&lt;/h3&gt;
&lt;p&gt;On the &lt;strong&gt;Review your pipeline YAML&lt;/strong&gt; screen, click &lt;strong&gt;Variables&lt;/strong&gt; in the top right corner.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsSetVariables.png"
alt="Azure DevOps review your pipeline YAML screen with Variables button" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;In the &lt;strong&gt;Variables&lt;/strong&gt; pane, click &lt;strong&gt;New Variable&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add a new variable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the variable name to &lt;strong&gt;DATA_IMAGE_NAME&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Set the value to &lt;strong&gt;adventure-works:2019&lt;/strong&gt;, or use the &lt;a href="https://docs.spawn.cc/other/public-data-images"&gt;public image of your choice&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Click &lt;strong&gt;OK&lt;/strong&gt; at the bottom of the pane.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsDataImageVariable.png"
alt="Azure DevOps pane when adding a new variable" width="400"&gt;
&lt;/figure&gt;
&lt;p&gt;In the &lt;strong&gt;Variables&lt;/strong&gt; pane, click the &lt;strong&gt;plus sign&lt;/strong&gt; to add a second variable.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsAddVariable.png"
alt="Azure DevOps input pane for variable name and value" width="400"&gt;
&lt;/figure&gt;
&lt;p&gt;To get the value for this variable, you need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.spawn.cc/getting-started/installation"&gt;Install the Spawn command line&lt;/a&gt; on a computer, if you have not done so already. (This should be fast: the page guides you to log into the Spawn web app with GitHub, download the Spawn command line executable, save it to a folder, add the folder to your path, and then run &lt;code&gt;spawnctl auth&lt;/code&gt; in a terminal.)&lt;/li&gt;
&lt;li&gt;Run &lt;a href="https://docs.spawn.cc/commands/spawnctl-accesstoken-create"&gt;the following command&lt;/a&gt; to create an access token:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;spawnctl create access-token --purpose &amp;#34;Spawn access token for pipeline test&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Copy the token from the terminal to your clipboard.&lt;/p&gt;
&lt;p&gt;Now, back in the Azure DevOps &lt;strong&gt;variables&lt;/strong&gt; pane, add a second variable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the variable name to &lt;strong&gt;SPAWNCTL_ACCESS_TOKEN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Past the value of your access token from your clipboard&lt;/li&gt;
&lt;li&gt;Tick off the &amp;ldquo;keep this value secret&amp;rdquo; box to protect your access token&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Click &lt;strong&gt;OK&lt;/strong&gt; at the bottom of the pane.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsSpawnAccessTokenVariable.png"
alt="Azure DevOps variables pane to add second variable." width="400"&gt;
&lt;/figure&gt;
&lt;p&gt;Back in the main &lt;strong&gt;Variables&lt;/strong&gt; pane, click &lt;strong&gt;Save&lt;/strong&gt; at the bottom of the screen.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsSaveVariables.png"
alt="Azure DevOps variables pane with final save button for variable additions" width="400"&gt;
&lt;/figure&gt;
&lt;h3 id="save-and-run-your-pipeline"&gt;Save and Run Your Pipeline&lt;/h3&gt;
&lt;p&gt;As a quick recap, so far we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Created a starter YAML pipeline&lt;/li&gt;
&lt;li&gt;Replaced the code with YAML to work with Spawn&lt;/li&gt;
&lt;li&gt;Added two variables to the pipeline and saved them&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we need to save the pipeline itself. On the &lt;strong&gt;Review your pipeline YAML&lt;/strong&gt; screen, click &lt;strong&gt;Save and run&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsSavePipeline.png"
alt="Azure DevOps save and run button for the pipeline" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;In the &lt;strong&gt;Save and run&lt;/strong&gt; pane which appears, click &lt;strong&gt;Save and run&lt;/strong&gt; in the bottom right corner.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsSaveAndRunPipeline.png"
alt="Azure DevOps confirmation that you really want to save and run" width="400"&gt;
&lt;/figure&gt;
&lt;p&gt;You will now be taken to a screen where you can watch your Pipeline job be queued and then run. If all has gone well, you should see your job succeed in a relatively short amount of time.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDevOpsJobSucceeded.png"
alt="Azure DevOps screen to review the pipeline progress and status" width="900"&gt;
&lt;/figure&gt;
&lt;h3 id="check-out-the-data-container-created-by-the-pipeline"&gt;Check Out the Data Container Created by the Pipeline&lt;/h3&gt;
&lt;p&gt;Our pipeline asked Spawn to create a copy of the AdventureWorks sample database with a lifetime of 20 minutes. We can connect to that database in SQL Server Management Studio or Azure Data Studio if we&amp;rsquo;d like to check it out.&lt;/p&gt;
&lt;p&gt;We let Spawn name the database container in this case.&lt;/p&gt;
&lt;p&gt;Open a terminal, and run the following command to get a list of all your data containers.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;spawnctl get data-containers&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will return a list of your containers with their metadata.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/spawnDataContainerList.png"
alt="spawn command line listing data containers created" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;Next, plug the name of your data container into the following command.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;spawnctl get data-container adventure-works-ebnmatep -o json&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will output connection information for your database.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/spawnDataContainerJSON.png"
alt="spawn command line outputting json with full connection details" width="900"&gt;
&lt;/figure&gt;
&lt;p&gt;Note from the output:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Data Source connection string, including the port&lt;/li&gt;
&lt;li&gt;The username is sa&lt;/li&gt;
&lt;li&gt;A random password has been generated&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use this information to connect to the SQL Server instance using the IDE of your choice.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureDataStudioConnectToSpawn.png"
alt="Instance connection screen in Azure Data Studio with details on spawn instance" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;If you enjoy using Azure Data Studio, &lt;a href="https://github.com/red-gate/spawn-ads-extension"&gt;the Spawn extension for Azure Data Studio&lt;/a&gt; makes connecting to your Spawn instances simple.&lt;/p&gt;
&lt;h2 id="other-ways-to-get-started-with-spawn"&gt;Other Ways to Get Started with Spawn&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to play around with Spawn locally, &lt;a href="https://docs.spawn.cc/getting-started/installation"&gt;follow the Spawn Getting Started tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d prefer to use Spawn with GitHub Actions, &lt;a href="https://docs.spawn.cc/cicd/github-actions"&gt;there&amp;rsquo;s a tutorial for that as well&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tsql2sday-logo.jpg" width="100"&gt;
&lt;/figure&gt;
&lt;h2 id="thanks-for-the-great-tsqltuesday-topic"&gt;Thanks for the Great TSQLTuesday Topic&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve wanted to write this article for a while, but I kept not getting around to it. Thanks to &lt;a href="https://twitter.com/nocentino"&gt;Anthony Nocentino&lt;/a&gt; for the writing prompt.&lt;/p&gt;</description></item><item><title>The HBO Max Integration Test Email Means You Should Make Automation Safer: For Everyone</title><link>https://kendralittle.com/2021/06/18/make-your-tech-safer-for-your-interns-and-everyone-else/</link><pubDate>Fri, 18 Jun 2021 16:15:47 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/06/18/make-your-tech-safer-for-your-interns-and-everyone-else/</guid><description>&lt;p&gt;When I woke up today in the UK, Twitter was alive with jokes, hot takes, and sympathy about an email sent out to millions of folks on a contact list for HBO Max featuring the subject line, &amp;ldquo;Integration Test Email #1&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the email looked like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/IntegrationTestEmailNumber1.png"
alt="Screenshot of the HBO Max integration test email that was sent to subscribers" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;This email went out to more than subscribers: just about everyone with an email address got one. (Except me! I felt left out. My partner got one, so it&amp;rsquo;s in the family, though.)&lt;/p&gt;
&lt;h2 id="what-happened"&gt;What Happened?&lt;/h2&gt;
&lt;p&gt;The folks at HBO Max explained a little bit about how so many people were involved in this integration test:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/hbo-max.png"
alt="Screenshot of HBO Max&amp;#39;s explanation about the integration test email" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="no-really-what-actually-happened"&gt;No Really, What Actually Happened?&lt;/h2&gt;
&lt;p&gt;I give the folks at HBO Max credit for the supportive tone in their tweet. As someone who has had some big &amp;ldquo;oops!&amp;rdquo; moments with databases and production systems, I know the feeling of REALLY wanting to turn back time after you realize that you&amp;rsquo;ve accidentally caused things to go horribly wrong.&lt;/p&gt;
&lt;p&gt;But it wasn&amp;rsquo;t &amp;ldquo;the intern&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This only happens to an intern (or even to a Senior Engineer) if there aren&amp;rsquo;t safety measures in place. We &lt;em&gt;all&lt;/em&gt; need safety measures: interns, engineers of all levels, and customers.&lt;/p&gt;
&lt;h2 id="two-key-pathways-to-protect"&gt;Two Key Pathways to Protect&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pathway 1: Restoring production datasets into development environments&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How many of us have ever been at a company where we restored the production database to the development environment, and then at one point someone accidentally emailed all the customers?&lt;/p&gt;
&lt;p&gt;I have. When I ask others this question at database-related events, lots and lots of folks raise their hands. This is an often-told story.&lt;/p&gt;
&lt;p&gt;This happens &lt;em&gt;all the time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There are reasons why production-like datasets are necessary in dev and test environments. There are also important reasons to redact and/or mask sensitive parts of that data.&lt;/p&gt;
&lt;p&gt;Redacting and masking sensitive data protects our staff from sending out &amp;ldquo;Integration Test Email #1&amp;rdquo; from the development environment. It also protects our customers. Development datasets are also a prime target for hackers who use phishing techniques to obtain credentials that allow them to harvest valuable data from development environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pathway 2: Safety checks in pipelines&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While it&amp;rsquo;s most likely that this email was caused by a production dataset being used in a development environment, it&amp;rsquo;s also possible that this was caused by an automated deployment pipeline with few or no safety checks.&lt;/p&gt;
&lt;p&gt;Automation can either make things very &lt;em&gt;unsafe&lt;/em&gt;, or very &lt;em&gt;safe&lt;/em&gt;: it&amp;rsquo;s all in how your team implements automation.&lt;/p&gt;
&lt;p&gt;Making automation pipelines safer doesn&amp;rsquo;t necessarily mean making them slower. With most automation systems, one can implement a combination of automated tests to catch problems. Also consider checks to estimate change risk, such as the number of emails which would be sent. You may choose to allow low-risk changes to flow more freely through the system, while higher-risk changes require manual review.&lt;/p&gt;
&lt;h2 id="what-to-learn-from-integration-test-email-1"&gt;What to Learn from Integration Test Email #1&lt;/h2&gt;
&lt;p&gt;The main thing to remember is that &lt;em&gt;this can happen to anyone&lt;/em&gt;. We all can be the one to make a mistake.&lt;/p&gt;
&lt;p&gt;The key thing is to work towards making things safer, and increasingly making it less likely to make mistakes.&lt;/p&gt;
&lt;p&gt;Take the time to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Look at whether production data is being restored into development environments without masking of personal and sensitive data. If it is, start up a conversation about fixing that.&lt;/li&gt;
&lt;li&gt;Identify the safety checks in your automated pipelines, and if there are improvements you can initiate here to make deployments safer for everyone.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Managing Drift in Automated Deployments to SQL Server Databases</title><link>https://kendralittle.com/2021/06/04/managing-drift-automated-deployments-sql-server/</link><pubDate>Fri, 04 Jun 2021 12:17:48 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/06/04/managing-drift-automated-deployments-sql-server/</guid><description>&lt;p&gt;One big gotcha that teams often encounter when automating deployments for databases is that it&amp;rsquo;s difficult (or sometimes impossible) to ensure that all changes to the production database are performed through the automation pipeline.&lt;/p&gt;
&lt;p&gt;These out-of-band changes case the production database to &amp;ldquo;drift&amp;rdquo; away from the schema as defined in version control.&lt;/p&gt;
&lt;p&gt;Why does this happen, and what do you do when your production database gets modified outside of your automated deployment pipeline?
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Database_Axe_Signed.png"
alt="Illustration of a database with an axe" width="200"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id="how-production-drift-happens"&gt;How Production Drift Happens&lt;/h2&gt;
&lt;p&gt;I find that there are three common causes of production database drift.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Process lag&lt;/strong&gt;: Production drift is especially common when process changes are occurring and the automated deployment process is newly established. In this case, not everyone is quite on board with the new deployment procedure and changes continue to flow into production via older processes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Oops!&amp;rdquo;&lt;/strong&gt;: Another common cause of production drift is accidental deployments. It&amp;rsquo;s pretty darn easy to deploy something to the wrong database. Sometimes the person who does this realizes their mistake, and sometimes they don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Whatever it takes&amp;rdquo; requirements&lt;/strong&gt;: Some business critical databases rely on immediate remediation for certain types of issues to be performed by subject matter experts as soon as possible, and core stakeholders do not even wish to wait for a pipeline to execute to deploy corrective changes once they have been identified. An example of this could be an index being created to remediate a critical performance problem that unexpectedly appeared. (&lt;em&gt;Note&lt;/em&gt;: many teams find ways to optimize their pipelines so emergency changes may be deployed incredibly quickly, but this varies.)&lt;/p&gt;
&lt;h2 id="automatically-reverting-drift-is-dangerous"&gt;Automatically Reverting Drift Is Dangerous&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Database_Fire_Signed.png"
alt="Illustration of a database on fire" width="220"&gt;
&lt;/figure&gt;
&lt;p&gt;Some folks like the idea of wiping out any drift when the next automated deployment occurs.&lt;/p&gt;
&lt;p&gt;This can be done using &amp;ldquo;state&amp;rdquo; based deployments for SQL Server: one can do this when deploying Redgate&amp;rsquo;s SQL Source Control projects using SQL Compare (or an automated pipeline), or when deploying Microsoft&amp;rsquo;s Database Projects (SSDT). With this approach, code is automatically generated to apply the schema in the project to the target database. If anything has changed in the target database since the last deployment and it wasn&amp;rsquo;t incorporated into the schema in the project, it automatically be eliminated.&lt;/p&gt;
&lt;p&gt;But automatically reverting drift is risky.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can cause a performance regression&lt;/strong&gt; - If an emergency fix was put into place for a critical performance problem, that problem is very likely to come back if we automatically revert the fix.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You probably didn&amp;rsquo;t test this change&lt;/strong&gt;: No automatically generated code is guaranteed to be 100% perfect 100% of the time. If changes were made to production and not to other environments and you automatically generate and run code to revert it, that code probably wasn&amp;rsquo;t tested anywhere else. Do you really want that code to run?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can lose data&lt;/strong&gt; - In some cases, the drift might have done something like create a new column or table and persist some data there. Is it really safe to drop that column or table? We won&amp;rsquo;t know unless we take time to investigate.&lt;/p&gt;
&lt;p&gt;Generally, we want to either prevent drift, or we want to be alerted to the drift and to investigate it.&lt;/p&gt;
&lt;h2 id="option-1-alert-when-drift-occurs"&gt;Option 1: Alert When Drift Occurs&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/database_cat_signed.png"
alt="Illustration of a cat with a database" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;One of the best things that you can do is to monitor for database drift and alert when it happens. Establish a procedure to follow up on the alert:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Revert the change&lt;/li&gt;
&lt;li&gt;Incorporate the change into your project retroactively&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Grant Fritchey wrote up some &lt;a href="https://sqlmonitormetrics.red-gate.com/database-drift-monitoring-unauthorized-object-changes/"&gt;sample code for monitoring for and alerting on drift in SQL Monitor&lt;/a&gt;. This approach uses an Extended Events Trace and SQL Monitor&amp;rsquo;s Custom Alert functionality.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using a different monitoring solution, it&amp;rsquo;s absolutely worth investigating if you can implement monitoring for database drift.&lt;/p&gt;
&lt;h2 id="option-2-automatically-incorporate-drift-into-your-development-environment"&gt;Option 2: Automatically Incorporate Drift into Your Development Environment&lt;/h2&gt;
&lt;p&gt;Another option is to regularly check for production drift and proactively pull it into your development environment. Ideally, this should be an automated solution or you are likely to miss the drift.&lt;/p&gt;
&lt;p&gt;If you have a schema snapshot tool, this can be done by automating schema snapshots of the production environment and copying the snapshots to your development environments. Then run a comparison against your development database or project to check for drift.&lt;/p&gt;
&lt;p&gt;For Redgate SQL Compare users, there&amp;rsquo;s even &lt;a href="https://www.red-gate.com/simple-talk/blogs/compare-those-hard-to-reach-servers-with-sql-snapper/"&gt;a tool called &amp;ldquo;SQL Snapper&amp;rdquo;&lt;/a&gt; that is designed to help make taking these snapshots more easily.&lt;/p&gt;
&lt;p&gt;For others, Microsoft provides &lt;a href="https://docs.microsoft.com/en-us/sql/tools/sqlpackage/sqlpackage"&gt;the ability to extract the schema from a database with SqlPackage.exe&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="option-3-prevent-drift-altogether"&gt;Option 3: Prevent Drift Altogether&lt;/h2&gt;
&lt;p&gt;One very popular use of &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/triggers/ddl-triggers"&gt;DDL Triggers in SQL Server&lt;/a&gt; is to prevent accidental or out-of-process database changes.&lt;/p&gt;
&lt;p&gt;These are a bit like a child-safety lock: you need to be able to disable the trigger in order to make schema changes. This means that it&amp;rsquo;s always possible for an adminsitrator to disable the triggers and make a change.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s generally fine, the cause of drift is often ignorance, forgetfulness, or accident rather than malicious users. But it does mean that this approach pairs well with also adding an alert to monitoring to check for drift, too.&lt;/p&gt;</description></item><item><title>Why NoSQL Database Adoption Is Not a One Way Journey</title><link>https://kendralittle.com/2021/05/27/nosql-database-adoption-isnt-a-one-way-journey/</link><pubDate>Thu, 27 May 2021 08:34:12 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/27/nosql-database-adoption-isnt-a-one-way-journey/</guid><description>&lt;p&gt;A coworker shared with me recently that a customer is wholly investing in adopting non-relational datastores.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Is NoSQL taking over?&amp;rdquo; they asked.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/rob-wicks-yVuRzuqArkg-unsplash.jpg"
alt="A &amp;#39;one way&amp;#39; road sign that has been knocked over on the ground" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;In my experience, organizations who go &amp;ldquo;all in&amp;rdquo; on non-relational databases end up with a mixed environment. In other words, they continue heavily using relational databases. They realize that they need to invest in doing well with every kind of database they use for mission-critical data.&lt;/p&gt;
&lt;h2 id="at-the-beginning-of-the-journey"&gt;At the Beginning of the Journey&lt;/h2&gt;
&lt;p&gt;Key team members and leaders get on board with investing heavily in working with non-relational datastores. Typically there are a few headline use cases where non-relational databases fit really well.&lt;/p&gt;
&lt;p&gt;This gives a feeling that these types of databases will work well for every system.&lt;/p&gt;
&lt;h2 id="over-time-some-projects-succeed-and-some-fail"&gt;Over Time, Some Projects Succeed and Some Fail&lt;/h2&gt;
&lt;p&gt;Generally, teams do find use cases where the non-relational databases work very well.&lt;/p&gt;
&lt;p&gt;They also find plenty of cases where moving to a non-relational datastore adds complexity and reliability goes down.&lt;/p&gt;
&lt;h2 id="relational-databases-are-good-at-well-relations-between-data"&gt;Relational Databases Are Good at, Well, Relations Between Data&lt;/h2&gt;
&lt;p&gt;Relational databases provide well-documented, simple ways to efficiently store data and to join data back together to return meaningful results. It&amp;rsquo;s relatively quick and efficient to get a project off the ground using a relational datastore. Modern hardware and cloud computing patterns also make this more scalable than ever.&lt;/p&gt;
&lt;p&gt;But this doesn&amp;rsquo;t fit every use case.&lt;/p&gt;
&lt;p&gt;Sometimes it is better to have a database designed specifically to store and retrieve documents. Or to use specialized methods to store and query complex relationships using graphs. Or to use a simple key-value mechanism.&lt;/p&gt;
&lt;h2 id="because-different-types-of-databases-are-suitable-for-different-use-cases"&gt;Because Different Types of Databases Are Suitable for Different Use Cases&lt;/h2&gt;
&lt;p&gt;Nearly every larger organization ends up with a mixed environment which includes plenty of relational databases. After the romance period is over, they realize they need to invest in processes, people, and tools for all of the technology in play.&lt;/p&gt;</description></item><item><title>My Sketchnotes from Redgate Level Up Week 2021</title><link>https://kendralittle.com/2021/05/24/sketchnotes-from-level-up-week-2021/</link><pubDate>Mon, 24 May 2021 17:39:17 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/24/sketchnotes-from-level-up-week-2021/</guid><description>&lt;p&gt;Redgate regularly holds an internal conference called Level Up week. In 2020 and 2021, this conference has been scaled to include multiple Redgate offices &lt;a href="https://medium.com/ingeniouslysimple/level-up-week-2020-how-we-evolved-our-internal-tech-conference-for-our-remote-first-world-e1fcd6eec95a"&gt;using a remote learning approach&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While this is an internal conference, I can share my drawings and notes from sessions I attended. I hope these inspire you with ideas on how you can contribute to learning in your own organization, or perhaps simply inspire you to give sketchnoting a try.&lt;/p&gt;
&lt;h2 id="why-sketchnote"&gt;Why Sketchnote?&lt;/h2&gt;
&lt;p&gt;I like sketchnoting for a couple of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sketchnoting during a talk helps me focus more on the content and think more deeply as I listen. (I struggle to focus while sitting completely still.)&lt;/li&gt;
&lt;li&gt;Looking at sketchnotes by other people often makes me interested in a topic which I might not otherwise look into at all. This often results in further reading on my talk, or deciding to attend talks or watch videos on those topics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically, I find sketchnotes interesting and inspiring.&lt;/p&gt;
&lt;h2 id="the-shape-up-product-development-methodology"&gt;The Shape Up Product Development Methodology&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/twalsh92"&gt;Tom Walsh&lt;/a&gt; shared his learnings and experiences using the Shape Up working methodology.&lt;/p&gt;
&lt;p&gt;This Product Development methodology was created and &lt;a href="https://basecamp.com/shapeup/webbook"&gt;shared by by Basecamp in 2019&lt;/a&gt;. (From what I can tell, this isn&amp;rsquo;t at all related to current events at Basecamp, but dig in and have your own critique.)&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sketchnote-shape-up-methodology.jpg"
alt="Sketchnote drawing about the Shape Up product development methodology" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="design-sprints"&gt;Design Sprints&lt;/h2&gt;
&lt;p&gt;Redgate&amp;rsquo;s &lt;a href="https://www.linkedin.com/in/tushita-gupta-14786576/"&gt;Tushita Gupta&lt;/a&gt; gave a terrific session with an overview of running a successful &lt;a href="https://en.wikipedia.org/wiki/Design_sprint"&gt;Design Sprint&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sketchnote-design-sprints.jpg"
alt="Sketchnote drawing about running successful Design Sprints" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="how-to-delegate-and-be-delegated-to"&gt;How to Delegate and Be Delegated To&lt;/h2&gt;
&lt;p&gt;We all know that delegation is a good idea. But most of us also don&amp;rsquo;t think enough about how to delegate well.&lt;/p&gt;
&lt;p&gt;This workshop, co-taught by &lt;a href="https://twitter.com/joseglima"&gt;Jose Lima&lt;/a&gt;, got me really thinking about how to do better with delegation, whether I&amp;rsquo;m the delegator or the delegatee.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sketchnote-how-to-delegate.jpg"
alt="Sketchnote drawing about how to delegate effectively and be delegated to" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="programming-with-types"&gt;Programming with Types&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/peschkaj"&gt;Jeremiah Peschka&lt;/a&gt; gave a talk about using types build intelligence deep within a program.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sketchnotes-programming-with-types.jpg"
alt="Sketchnote drawing about programming with types to build intelligence in programs" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="remote-workshops-that-dont-suck"&gt;Remote Workshops That Don&amp;rsquo;t Suck&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/neilturnerux"&gt;Neil Turner&lt;/a&gt; gave an excellent meta-workshop on giving workshops.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know about you, but I personally prefer remote workshops to in-person workshops. However, &lt;em&gt;all&lt;/em&gt; workshops are hard work: they can suck whether in-person or remote. I thought these were great tips on the remote variant.&lt;/p&gt;
&lt;p&gt;I also really appreciated that the first question Neil had us start with was asking us to always consider whether a workshop is the best option, or if perhaps this is a meeting that might be an email. (Or a document co-created asynchronously. Or a &lt;a href="https://www.mural.co/"&gt;mural board&lt;/a&gt; contributed to asynchronously. Etc.)&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sketchnote-remote-workshops-that-dont-suck.jpg"
alt="Sketchnote drawing about running effective remote workshops" width="600"&gt;
&lt;/figure&gt;
&lt;h2 id="thanks-redgate-for-a-great-level-up-week"&gt;Thanks Redgate for a Great Level Up Week&lt;/h2&gt;
&lt;p&gt;I feel very grateful to get to attend and participate in such a terrific conference each year. Thanks to all the Redgaters who sponsor, organize, and participate in this event.&lt;/p&gt;</description></item><item><title>Azure Static Web Apps Are Now Generally Available</title><link>https://kendralittle.com/2021/05/18/azure-static-sites-are-now-generally-available/</link><pubDate>Tue, 18 May 2021 07:31:05 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/18/azure-static-sites-are-now-generally-available/</guid><description>&lt;p&gt;I wrote recently about &lt;a href="https://kendralittle.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/"&gt;moving my blog from Wordpress to an Azure Static Site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Azure Static Web Apps have now moved out of Preview and are now generally available. A free tier has been announced which is great for personal blogs.&lt;/p&gt;
&lt;h2 id="a-free-tier"&gt;A Free Tier&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a screenshot from &lt;a href="https://azure.microsoft.com/en-gb/pricing/details/app-service/static/"&gt;https://azure.microsoft.com/en-gb/pricing/details/app-service/static/&lt;/a&gt; today:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/AzureStaticWebAppsPricingScreenshot20210518.png"
alt="Example free tier limits and pricing &amp;ndash; May 18, 2021" width="700"&gt;&lt;figcaption&gt;
&lt;p&gt;Example free tier limits and pricing &amp;ndash; May 18, 2021&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="new-features"&gt;New Features&lt;/h2&gt;
&lt;p&gt;New features were &lt;a href="https://azure.microsoft.com/en-us/blog/develop-production-scale-modern-web-apps-quickly-with-azure-static-web-apps/"&gt;announced&lt;/a&gt; at the time of GA.&lt;/p&gt;
&lt;p&gt;For casual bloggers who are getting started, the biggest among these is probably that Azure Static Sites now has full support for root domains &amp;mdash; no www or other subdomain is required anymore.&lt;/p&gt;
&lt;p&gt;Happy blogging!&lt;/p&gt;</description></item><item><title>Maintaining Balance While Retraining in a New Professional Area</title><link>https://kendralittle.com/2021/05/10/balance-while-retraining-new-professional-area/</link><pubDate>Mon, 10 May 2021 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/10/balance-while-retraining-new-professional-area/</guid><description>&lt;p&gt;It&amp;rsquo;s common to shift your professional focus multiple times over your career while working in tech. But moving into a new role often causes a lot of stress.&lt;/p&gt;
&lt;p&gt;In my recent lightning talk for &lt;a href="https://kendralittle.com/2021/04/21/free-virtual-event-mental-health-and-awareness-day-on-may-7th/"&gt;Mental Health and Awareness Day&lt;/a&gt;, I reflected on the lessons I&amp;rsquo;ve learned to set myself up for success and protect my health when taking on a new professional challenge.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/kt--9eNCP979zY-unsplash.jpg"
alt="A bird stradding two standing plants" width="250"&gt;
&lt;/figure&gt;
&lt;h2 id="ive-transitioned-between-a-variety-of-roles-over-the-course-of-my-working-life"&gt;I&amp;rsquo;ve Transitioned Between a Variety of Roles Over the Course of My Working Life&lt;/h2&gt;
&lt;p&gt;Looking back at my working hours, my roles have included working as a: Clown, Craft Store Clerk, Office Temp, Data Specialist, Tech Support, Build Ops Engineer, Database Administrator, Consultant and Small Business Owner, Developer Advocate&lt;/p&gt;
&lt;p&gt;Recently I&amp;rsquo;ve transitioned into a new role: Product Manager.&lt;/p&gt;
&lt;h2 id="i-enjoy-new-challenges-but-the-early-stages-are-quite-tricky"&gt;I Enjoy New Challenges, but the Early Stages Are Quite Tricky&lt;/h2&gt;
&lt;p&gt;I am a person who likes to contribute. This means that when I move into a new role with a steep learning curve, it&amp;rsquo;s generally unclear how I can best contribute and it can take a while to get up to speed.&lt;/p&gt;
&lt;p&gt;For me, the steeper the learning curve, the greater my stress and uncertainty.&lt;/p&gt;
&lt;p&gt;However, I&amp;rsquo;ve found that career shifts help me grow quite a bit, and are well worth doing!&lt;/p&gt;
&lt;p&gt;Over the years, I&amp;rsquo;ve learned to recognize where I tend to go wrong and to recognize how I can avoid these errors. This is a continual process, but one which I believe is worth the investment.&lt;/p&gt;
&lt;h2 id="recognizing-problem-patterns-and-building-good-habits-to-compensate"&gt;Recognizing Problem Patterns and Building Good Habits to Compensate&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Problem pattern: Focusing on the negative.&lt;/strong&gt; Change makes it trickier to recognize my own wins. Bad days will happen in any role, but it&amp;rsquo;s easy to blame myself for them when I&amp;rsquo;m in a new role.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Getting perspective:&lt;/strong&gt; I&amp;rsquo;ve found that having a sounding board at work is invaluable. If I can find a peer or colleague who is available for regular checkins, this can help me gain perspective on how I&amp;rsquo;m doing. It can also help me avoid catastrophizing bumps in the road.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem pattern: Overworking.&lt;/strong&gt; It also becomes very easy to work very long hours to try to get up to speed quickly. This tends to be one of the greatest traps I fall into. Working long hours feels helpful initially, but over time it tends to decrease my creativity and wear away at my prioritization skills.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting boundaries on time:&lt;/strong&gt; I&amp;rsquo;ve found that working predictable, defined hours makes me better at my job. Achieving this involves not only stopping work at the right time consistently, but also resisting the urge to look at emails and work channels during off-hours.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem pattern: An urge to be irreplaceable.&lt;/strong&gt; As someone who loves to contribute, it&amp;rsquo;s easy for me to fall into the trap of finding an area where I can offer unique value&amp;ndash; and not taking the time to empower my coworkers to offer this value without me. In my experience, if something is worth doing more than once, it&amp;rsquo;s generally worth either automating, or empowering others to do it!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Working as a team:&lt;/strong&gt; Prioritization and identifying the more important areas to contribute to are key to most roles that I&amp;rsquo;ve had. Practicing prioritization early in a role and validating these choices with my managers and my teammates is the best thing I can do to get started. Good prioritization also helps me make sure that I don&amp;rsquo;t get stuck in an area of repeating tasks, and can either automate or share the ability to take care of things with my colleagues.&lt;/p&gt;
&lt;h2 id="a-list-i-revisit-often"&gt;A List I Revisit Often&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t think I&amp;rsquo;ll ever find taking on new challenges easy. This will always be something that I work at improving. I find it well worth the work, however, and the work is lighter now that I&amp;rsquo;ve recognized where I tend to go wrong, and the habits that help me do well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set boundaries on working hours&lt;/li&gt;
&lt;li&gt;Disable work notifications or remove phone apps&lt;/li&gt;
&lt;li&gt;Say “no” to work activities you can no longer do&lt;/li&gt;
&lt;li&gt;Pause on extracurriculars if you need that time to relax&lt;/li&gt;
&lt;li&gt;Ask a colleague to have regular check-ins&lt;/li&gt;
&lt;li&gt;Practice recognizing feelings of self-doubt&lt;/li&gt;
&lt;li&gt;Practice acknowledging your progress&lt;/li&gt;
&lt;li&gt;Ask for help and delegate&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="writing-this-lightning-talk-was-helpful"&gt;Writing This Lightning Talk Was Helpful&lt;/h2&gt;
&lt;p&gt;One of the great things about public speaking is that it drives both learning and personal growth. These days, I&amp;rsquo;m careful about taking on too many speaking engagements and conferences in light of what I&amp;rsquo;ve said above about prioritization. However, this event and this topic came and just the right time as I&amp;rsquo;m finding my way as a new Product Manager.&lt;/p&gt;</description></item><item><title>How I Got Twitter Cards Working in Hugo with the Mainroad Theme</title><link>https://kendralittle.com/2021/05/07/how-i-got-twitter-cards-working-hugo-mainroad/</link><pubDate>Fri, 07 May 2021 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/07/how-i-got-twitter-cards-working-hugo-mainroad/</guid><description>&lt;p&gt;Hugo now has native support for Twitter Cards, but it took a few steps to get them working on my site in the way I wanted.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how I configured Twitter Cards in Hugo without any new shortcodes.&lt;/p&gt;
&lt;h2 id="whats-a-twitter-card"&gt;What&amp;rsquo;s a Twitter Card?&lt;/h2&gt;
&lt;p&gt;When you share a link on Twitter, it sometimes automatically adds an image to the tweet with a title and link at the bottom. This is a Twitter Card.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/TwitterCardExample.png"
alt="Screenshot of a Twitter card example showing a tweet with an image preview, title, and link at the bottom, featuring a drawing of a dog named Mister Little" width="400"&gt;&lt;figcaption&gt;
&lt;p&gt;A Twitter card featuring a drawing of our beloved dog, Mister Little&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Back when I used WordPress, I had a habit of setting the &amp;ldquo;featured image&amp;rdquo; for a post. Among other things, this featured image would typically be shown on the Twitter Card. After I &lt;a href="https://kendralittle.com/2021/05/03/moving-from-WordPress-to-an-azure-static-site-with-hugo/"&gt;switched from WordPress to Hugo&lt;/a&gt;, I noticed that when I tweeted links to my site, those pretty little cards weren&amp;rsquo;t showing up with my current configuration.&lt;/p&gt;
&lt;p&gt;I like to be active on Twitter, so I wanted to fix this.&lt;/p&gt;
&lt;h2 id="twitter-card-validator-and-metadata-in-html"&gt;Twitter Card Validator and Metadata in HTML&lt;/h2&gt;
&lt;p&gt;If you want to check out a Twitter card (or the lack thereof) without actually tweeting, Twitter provides an online &lt;a href="https://cards-dev.twitter.com/validator"&gt;Twitter Card validator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, you can inspect a page&amp;rsquo;s HTML and look for metadata about Twitter cards. This can be especially useful if you&amp;rsquo;re working with your local webserver (the Twitter card validator can&amp;rsquo;t do anything with &amp;ldquo;http://localhost:1313/&amp;rdquo; because it has no way to see your local webserver).&lt;/p&gt;
&lt;p&gt;You can &amp;ldquo;view page source&amp;rdquo; from your local webserver and look in the head portion of your HTML for meta tags that start with &amp;ldquo;twitter:&amp;rdquo;. Here is the way this metadata shows for this post on my local webserver, as I&amp;rsquo;m authoring it.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/TwitterCardMetadataExample.png"
alt="Screenshot of HTML source code showing Twitter card metadata tags including twitter:card, twitter:image, twitter:title, and twitter:description with the description set to &amp;#39;add description&amp;#39;" width="800"&gt;
&lt;/figure&gt;
&lt;h2 id="mistakes-i-made-in-configtoml"&gt;Mistakes I Made in config.toml&lt;/h2&gt;
&lt;p&gt;The Mainroad theme supports Twitter cards. When starting out, I had identified the twitter_cards setting in my config.toml file and I had set that to true. But my cards weren&amp;rsquo;t working. Why?&lt;/p&gt;
&lt;p&gt;One reason was that I was not specifying a default image to use for a Twitter card. Here is the default images setting that worked for me:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Mainroad-config-toml-twitter-cards.png"
alt="Screenshot of config.toml file showing the default images setting for Twitter cards with square brackets containing the image path" width="500"&gt;
&lt;/figure&gt;
&lt;p&gt;One mistake I made along the way: &lt;strong&gt;I accidentally omitted the square brackets&lt;/strong&gt;. That didn&amp;rsquo;t work at all, and it took some time to notice my mistake.&lt;/p&gt;
&lt;h2 id="you-can-manage-twitter-cards-in-detail-via-front-matter-in-hugo"&gt;You Can Manage Twitter Cards in Detail via Front Matter in Hugo&lt;/h2&gt;
&lt;p&gt;I like having a default TwitterCard, but I also like managing it for each page. Here is the &lt;a href="https://gohugo.io/content-management/front-matter/"&gt;Front Matter&lt;/a&gt; of this post as I&amp;rsquo;m authoring it in VSCode (or as I think of it, the header).&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Hugo-post-front-matter.png"
alt="Screenshot of Hugo post front matter in VSCode showing fields for title, date, categories, authors, description, toc, thumbnail, images, draft, and manually_reviewed" width="600"&gt;
&lt;/figure&gt;
&lt;p&gt;This might look like a lot of things to remember to list at the top of each post, but it&amp;rsquo;s not hard at all &amp;ndash; I have an &amp;ldquo;archetype&amp;rdquo; set up in Hugo which makes auto-populating this list easy when I create a new post. (More on that below.)&lt;/p&gt;
&lt;p&gt;I like managing these details on each page because it makes it simple for me &amp;ndash; I can see what the thumbnail is at a glance, if I have it set to the same thing as the Twitter Card or something else, etc. It&amp;rsquo;s really easy to change at any time.&lt;/p&gt;
&lt;h2 id="updating-the-front-matter-of-500-pages-using-a-regular-expression-find-and-replace"&gt;Updating the Front Matter of 500+ Pages Using a Regular Expression Find and Replace&lt;/h2&gt;
&lt;p&gt;I have more than 500 pages on this site. Wherever I have a thumbnail listed, I wanted to update the front matter on each one to list the Twitter card and default it to the same image as the thumbnail. (Maybe the thumbnail is supposed to be used as the Twitter card image by default in Hugo if the card image isn&amp;rsquo;t specified, I&amp;rsquo;m not clear&amp;ndash; but it wasn&amp;rsquo;t working on my site and this seemed like the simplest fix if I could get it done fast.)&lt;/p&gt;
&lt;p&gt;I was able to do this easily using the &amp;ldquo;Find and Replace in files&amp;rdquo; feature in VS code, with regular expressions enabled on my search and by making use of an &amp;ldquo;index&amp;rdquo; in the search.&lt;/p&gt;
&lt;p&gt;I searched in files for: &lt;code&gt;^thumbnail: (.*)\n&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I replaced this with: &lt;code&gt;thumbnail: $1 \nimages: [$1]\n&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/find-and-replace-regex-vscode.png"
alt="Screenshot of VS Code find and replace dialog showing a regular expression search pattern for thumbnail and replacement pattern to add images array"&gt;
&lt;/figure&gt;
&lt;p&gt;I found &lt;a href="https://dev.to/rfornal/vs-code-search-and-replace-regex-mn2"&gt;this post very helpful&lt;/a&gt; in figuring out the regular expression to use here.&lt;/p&gt;
&lt;h2 id="updating-my-archetype-file"&gt;Updating My Archetype File&lt;/h2&gt;
&lt;p&gt;As I mentioned above, I use an &lt;a href="https://gohugo.io/content-management/archetypes/"&gt;archetype&lt;/a&gt; in Hugo. This is essentially a template which will help me quickly create a new markdown file for a post with all the front matter I want pre-configured for me to fill in.&lt;/p&gt;
&lt;p&gt;I updated my archetype file for posts. Here&amp;rsquo;s what I currently have in the file, which in my case lives at archetypes/posts.md:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;---
title: &amp;#34;{{ replace .Name &amp;#34;-&amp;#34; &amp;#34; &amp;#34; | title }}&amp;#34;
date: {{ .Date }}
categories:
-
tags:
-
description: &amp;#34;add description&amp;#34;
toc: false
thumbnail:
images: []
draft: true
GHissueID:
---
Add post here.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To create a new post with the archetype, I run the following from the command line in my Hugo project, with whatever I want as the post title as the markdown file name:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;hugo new posts\hi-i-am-a-new-post.md&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That gives me a nice file to fill in with my post.&lt;/p&gt;
&lt;h2 id="this-was-a-fun-one-to-fix"&gt;This was a fun one to fix&lt;/h2&gt;
&lt;p&gt;There might be a more elegant way to solve this rather than that regular expression I used&amp;ndash; but I really enjoyed it!&lt;/p&gt;</description></item><item><title>How to Enable TCP/IP in SQL Server Developer Edition, Even If the Configuration Manager Is Missing</title><link>https://kendralittle.com/2021/05/05/how-to-enable-tcpip-in-sql-server-even-if-configuration-manager-is-missing/</link><pubDate>Wed, 05 May 2021 17:46:08 +0100</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/05/how-to-enable-tcpip-in-sql-server-even-if-configuration-manager-is-missing/</guid><description>&lt;p&gt;SQL Server&amp;rsquo;s Developer Edition installs with a different default network protocol configuration than Standard Edition and Enterprise Edition.&lt;/p&gt;
&lt;p&gt;Fixing this has gotten more complicated because it&amp;rsquo;s become common for the SQL Server Configuration Manager to not be installed on a developer&amp;rsquo;s workstation in an easily accessible way.&lt;/p&gt;
&lt;h2 id="many-editions-of-sql-server-install-with-tcpip-enabled-but-not-developer-edition"&gt;Many Editions of SQL Server Install With TCP/IP Enabled, but Not Developer Edition&lt;/h2&gt;
&lt;p&gt;If you don&amp;rsquo;t always work with Developer Edition, it&amp;rsquo;s easy to forget that it has a different default for the TCP/IP protocol.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t a bug &amp;ndash; Microsoft &lt;a href="https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/default-sql-server-network-protocol-configuration"&gt;has documented this&lt;/a&gt; (highlighting mine).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Edition&lt;/th&gt;
&lt;th&gt;New installation vs. previous installation is present&lt;/th&gt;
&lt;th&gt;Shared memory&lt;/th&gt;
&lt;th&gt;TCP/IP&lt;/th&gt;
&lt;th&gt;Named pipes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise&lt;/td&gt;
&lt;td&gt;New installation&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Disabled for network connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;New installation&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Disabled for network connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web&lt;/td&gt;
&lt;td&gt;New installation&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Disabled for network connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer&lt;/td&gt;
&lt;td&gt;New installation&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;&lt;code&gt;**DISABLED**&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Disabled for network connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation&lt;/td&gt;
&lt;td&gt;New installation&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Disabled for network connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server Express&lt;/td&gt;
&lt;td&gt;New installation&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;td&gt;Disabled for network connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All editions&lt;/td&gt;
&lt;td&gt;Previous installation is present but is not being upgraded.&lt;/td&gt;
&lt;td&gt;Same as new installation&lt;/td&gt;
&lt;td&gt;Same as new installation&lt;/td&gt;
&lt;td&gt;Same as new installation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All editions&lt;/td&gt;
&lt;td&gt;Upgrade&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Settings from the previous installation are preserved.&lt;/td&gt;
&lt;td&gt;Settings from the previous installation are preserved.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;But increasingly, developers do want to connect to Developer Edition SQL Server instances over TCP/IP. Maybe those development instances are being used for a build or for testing purposes. Or maybe they are simply using a development tool that requires TCP/IP.&lt;/p&gt;
&lt;p&gt;To fix this&amp;hellip;&lt;/p&gt;
&lt;h2 id="1-first-run-the-program-sql-server-configuration-manager-or-find-it-in-computer-management"&gt;1. First, run the program &amp;ldquo;SQL Server Configuration Manager&amp;rdquo; (or find it in Computer Management)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Option 1:&lt;/strong&gt; The traditional way to fix this is in an application named &amp;ldquo;SQL Server Configuration Manager&amp;rdquo;, which is (sometimes) installed when SQL Server Developer Edition is installed. You can find this in the Windows Start menu or search bar. If you don&amp;rsquo;t see the SQL Server Configuration Manager installed&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2&lt;/strong&gt;: Run the &amp;ldquo;Computer Management&amp;rdquo; app. This can be started from the Windows Start menu or search bar. The command line to start this is &lt;code&gt;compmgmt.msc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Expand &amp;ldquo;Services and Applications&amp;rdquo; at the bottom of the left menu.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ComputerManagement-SQLServerConfigurationManager.png"
alt="Screenshot of Computer Management showing SQL Server Configuration Manager" width="650"&gt;
&lt;/figure&gt;
&lt;p&gt;If you have more than one version of SQL Server installed, you will see more than one &amp;ldquo;SQL Server Configuration Manager&amp;rdquo; snap-in available. ou generally want to choose the highest version, but to tell which one that is, you will need to click into &amp;ldquo;SQL Server Services&amp;rdquo; in each one and see which one lists the most SQL Server instances.&lt;/p&gt;
&lt;p&gt;Now you have all the functionality of the SQL Server Configuration Manager in front of you. (It&amp;rsquo;s just this snap-in.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://github.com/potatoqualitee"&gt;Chrissy LeMaire&lt;/a&gt; for this tip about Computer Management in the comments. I had no idea!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 3&lt;/strong&gt;: If Computer Management doesn&amp;rsquo;t work for you for some reason, you could also add snap-ins to the Microsoft Management Console:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From a terminal or the windows search bar, start the Microsoft Management Console by running: &lt;code&gt;mmc.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Go to “File”, then “Add/Remove Snap-in”&lt;/li&gt;
&lt;li&gt;Find &amp;ldquo;SQL Server Configuration Manager&amp;rdquo; in the list of available snap-ins and click &amp;ldquo;Add&amp;rdquo; to move it to the right&lt;/li&gt;
&lt;li&gt;Click &amp;ldquo;OK&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have more than one version of SQL Server installed, you will see more than one &amp;ldquo;SQL Server Configuration Manager&amp;rdquo; snap-in available. You generally want to choose the highest version for the reasons above. This may take some trial and error. You have the option to &amp;ldquo;Save&amp;rdquo; your Microsoft Management Console configuration (under the File menu) so it&amp;rsquo;s easier to re-open your configuration the next time you run MMC.exe.&lt;/p&gt;
&lt;h2 id="2-next-enable-the-tcpip-protocol-for-the-instance"&gt;2. Next, enable the TCP/IP protocol for the instance&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Expand &amp;ldquo;SQL Server Network Configuration&lt;/li&gt;
&lt;li&gt;Click &amp;ldquo;protocols for &amp;lt;the name of your instance&amp;gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Find the TCP/IP protocol in the details pane, right-click it, and select &amp;ldquo;Enable&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/EnableTCPIP.png"
alt="Screenshot showing how to enable TCP/IP protocol in SQL Server Configuration Manager" width="650"&gt;
&lt;/figure&gt;
&lt;h2 id="3-finally-restart-the-sql-server-instance"&gt;3. Finally, restart the SQL Server Instance&lt;/h2&gt;
&lt;p&gt;You will see a message that the SQL Server instance needs to be restarted for this to take effect.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &amp;ldquo;SQL Server Services&amp;rdquo;&lt;/li&gt;
&lt;li&gt;In the right pane, right-click the instance to restart&lt;/li&gt;
&lt;li&gt;I typically choose to stop it, wait a beat, and then start it separately &amp;ndash; just so if anything fails I know what bit it was on when it hit the problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ComputerManagement-SQLServerConfigurationManager-ServiceStopStart.png"
alt="Screenshot showing how to stop and start SQL Server service in Computer Management" width="650"&gt;
&lt;/figure&gt;
&lt;h2 id="but-why"&gt;But, Why?&lt;/h2&gt;
&lt;p&gt;This configuration default has never actually made much sense to me, personally. I&amp;rsquo;ve always worked in environments where it&amp;rsquo;s been useful to allow remote connections to developer SQL Server instances.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve heard the argument before that it&amp;rsquo;s more secure to default an instance to this configuration and only enable TCP/IP connections if shared memory / Named Pipes aren&amp;rsquo;t sufficient. But if that was the case, wouldn&amp;rsquo;t this be the default for &lt;em&gt;all&lt;/em&gt; editions? :thinking:&lt;/p&gt;
&lt;p&gt;In any case, this default has been in place for a long time, and I think it&amp;rsquo;s unlikely to change anytime soon.&lt;/p&gt;</description></item><item><title>Moving From WordPress to an Azure Static Site with Hugo</title><link>https://kendralittle.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/</link><pubDate>Mon, 03 May 2021 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/</guid><description>&lt;p&gt;I&amp;rsquo;ve moved from WordPress to an Azure Static website built with Hugo. The conversion, including grooming all my old posts and a special setup for my &lt;a href="https://kendralittle.com/coursesbytitle/"&gt;free courses&lt;/a&gt; took up most of my personal time for a week (including a 4 day weekend).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s why I made the change. I&amp;rsquo;ll also share the basic components I chose for my site, the tools and steps I used in the conversion, and some lessons learned from the implementation.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/jessica-ruscello-lUtPqjz5D5k-unsplash.jpg"
alt="View of rocks jutting up in the ocean with the sunset behind them." width="230"&gt;
&lt;/figure&gt;
This is going to be a long one, so buckle up! :seat:&lt;/p&gt;
&lt;h2 id="why-i-ditched-wordpress-after-12-years"&gt;Why I Ditched WordPress After ~12 Years&lt;/h2&gt;
&lt;p&gt;I used WordPress for blogging from 2009 to 2021. Even after some cleanup, I have more than 500 blog posts. So I had a good amount of investment with WordPress. I knew that changing how I manage and publish my blog content would be a lot of work.&lt;/p&gt;
&lt;p&gt;But I had significant pains with WordPress:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;High Cost&lt;/strong&gt;: I used an expensive WordPress host when I was running my own business but no longer wanted to pay the big bucks for hosting when I made my video content free and my site returned to &amp;ldquo;hobby&amp;rdquo; status. There are additional costs with WordPress for plugins for things like backups, security scanning, and flexible themes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bad Performance&lt;/strong&gt;: When I downgraded to a cheaper host, my performance tanked. My site was often so slow that it was hard to tell if it was online or not, even with Cloudflare supposedly set up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low Portability&lt;/strong&gt;: It took many hours to even get my WordPress site migrated to the cheaper host&amp;ndash; just figuring out how to get the backups I had taken to work with a migration took hours with support from the backup tool company. (Turns out most of the tooling is optimized to restore to the &lt;em&gt;same&lt;/em&gt; host, but that doesn&amp;rsquo;t mean you can&amp;rsquo;t keep trying to do it and having it fail :facepalm:.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Significant Complexity&lt;/strong&gt;: Once it was migrated, troubleshooting the performance issues with the new host was the cause of a lot of frustration. At times there was clearly an issue with underpowered hardware, but nobody could help me figure out why everything just generally sucked. Maybe there was some misconfiguration in my setup, but with a MySQL database, webserver, plugins, themes, Cloudflare, and who knows what else was going on at the host involved &amp;ndash; I just had no interest in troubleshooting it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Hassles&lt;/strong&gt;: The more complex a system is, the harder it is to prevent vulnerabilities. It&amp;rsquo;s fairly common for WordPress sites to be hacked and have malicious code inserted to advertise for spammy links &amp;ndash; this happened to me once a few years back.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="i-considered-throwing-my-whole-site-away"&gt;I Considered Throwing My Whole Site Away&lt;/h2&gt;
&lt;p&gt;I wasn&amp;rsquo;t having fun with the blog anymore after I&amp;rsquo;d migrated to the Terrible WordPress Host. Troubleshooting WordPress wasn&amp;rsquo;t appealing. I didn&amp;rsquo;t want to spend a bunch of money to have someone else do it, either. I considered abandoning the blog and simply moving on. :wastebasket: :raccoon:&lt;/p&gt;
&lt;p&gt;The main reason I didn&amp;rsquo;t do that was that those friends in the community who DM&amp;rsquo;d me about my site being down mentioned that they found my content useful. This feedback helped me make the right decision. Thanks, friends. :revolving_hearts:&lt;/p&gt;
&lt;p&gt;So I looked around to see if there was a newer way to blog which would be more fun for me, and which wouldn&amp;rsquo;t have all these problems.&lt;/p&gt;
&lt;h2 id="why-a-static-website"&gt;Why a Static Website?&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/iwan-shimko-PhciG8fpRKw-unsplash.jpg"
alt="A photo of three polaroid photographs." width="230"&gt;
&lt;/figure&gt;
As someone who spends most of her time thinking about databases, I didn&amp;rsquo;t even know what a &lt;a href="https://en.wikipedia.org/wiki/Website#Static_website"&gt;static site&lt;/a&gt; was until I started looking into new options for my blog.&lt;/p&gt;
&lt;p&gt;In the early days of the internet, all web pages were pretty simple: just some HTML. Eventually with some CSS styling. Static websites are a return to this concept: when your browser loads a page on a static site, it&amp;rsquo;s mostly just loading pre-baked HTML and CSS.&lt;/p&gt;
&lt;p&gt;This contrasts to &lt;a href="https://en.wikipedia.org/wiki/Website#Dynamic_website"&gt;dynamic websites&lt;/a&gt;, where pages may load different things for different people. There are also generally more types of interactions available on dynamic sites. But with the flexibility of dynamic sites comes the complexity and potential for related issues I mentioned above.&lt;/p&gt;
&lt;p&gt;There are now a few open-source static website generators which are very popular both for blogs and other types of websites. The most popular are &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt;, &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, and &lt;a href="https://www.gatsbyjs.com/"&gt;Gatsby&lt;/a&gt;. The main benefits of using a static site built with one of these generators are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Low or No Cost&lt;/strong&gt;: There are quite a few low-cost or free hosting options for static sites, including &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt; (free), &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview"&gt;Azure Static Web Apps&lt;/a&gt; (Update May 18 2021: &lt;a href="https://kendralittle.com/2021/05/18/azure-static-sites-are-now-generally-available/"&gt;now Generally Available with a free tier&lt;/a&gt;), and free plans on providers like &lt;a href="https://www.netlify.com/pricing/"&gt;Netlify&lt;/a&gt;. Static site generators like &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; and &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; are typically open source and completely free to use. An active community of users of these static site generators have created a large amount of free themes, many of which are eminently customizable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Performance&lt;/strong&gt;: By pre-building the content and minimizing what the client browser does when loading pages, static sites can offer very high performance and fast page load time, even while having lower costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Shifted Left&amp;rdquo; Complexity&lt;/strong&gt;: Using a static site generator can seem quite complex if you aren&amp;rsquo;t used to working with a bit of code, version control, and cloud tooling. But if these things are appealing to you, the complexity is all in a learning curve. Once you&amp;rsquo;re on board, the normal process of blogging becomes quite simple, and the static site itself is generally quite simple in how it operates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Portability&lt;/strong&gt;: Having the contents of your site all in source code gives you so much more portability than you have by using a content management system which keeps much of the content in a database. I am a huge fan of databases &amp;ndash; I&amp;rsquo;ve spent my entire professional career thinking about how to best work with databases! But I don&amp;rsquo;t have a &amp;ldquo;golden hammer&amp;rdquo; view of databases. It makes much more sense to me that my personal blog just involve a bunch of text files and images which are checked into version control. This is easier to manage and much more portable long term. Not only can I move my static site easily between different hosts by simply deploying elsewhere, I also have a lot more options if I want to switch to something different later on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better Security&lt;/strong&gt;: Static sites are generally much more simple than dynamic sites and have a lower surface area for attack. Also, as long as the repo holding my code is secure, I always have the option of clearing out my live environment and redeploying everything from scratch if I need to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The downsides of static sites are that they are less accessible to people who prefer to work in a lower-tech fashion.&lt;/p&gt;
&lt;p&gt;It also can take a little extra work to include interaction in your website and often involves integrating third party services into your site. You&amp;rsquo;ll see that I have workarounds for blog comments, newsletter subscription, and a comment page below, all of which leverage an external provider.&lt;/p&gt;
&lt;h2 id="why-i-chose-hugo-and-azure-static-web-apps"&gt;Why I Chose Hugo and Azure Static Web Apps&lt;/h2&gt;
&lt;p&gt;I didn&amp;rsquo;t have a tiny project &amp;ndash; remember, I had ~500 blog posts to migrate and a desire to do a custom setup to still offer ~30 free video courses online. Also, the performance of my current WordPress site was just abysmal. I frequently got DMs on Twitter from friends nicely letting me know that my site wasn&amp;rsquo;t working :cold_sweat:.&lt;/p&gt;
&lt;p&gt;It felt advisable to ask my network for advice.&lt;/p&gt;
&lt;p&gt;My first thought was that &lt;a href="https://twitter.com/cl"&gt;Chrissy LeMaire&lt;/a&gt; had &lt;a href="https://blog.netnerds.net/2020/08/migrating-my-WordPress-sites-to-github-pages/"&gt;written about migrating her WordPress site to GitHub Pages&lt;/a&gt;. But when I mentioned this on Twitter, &lt;a href="https://twitter.com/cl/status/1385643480593141764"&gt;Chrissy advised&lt;/a&gt; that she might approach this a different way if she had it to do again:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good intermediate solution but not a good final solution! I haven&amp;rsquo;t blogged much since then because it&amp;rsquo;s a pain 😭 In retrospect, I&amp;rsquo;d look for a WordPress to Markdown plugin, and put the work in upfront.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My next thought was&amp;hellip; hey, didn&amp;rsquo;t my partner do something like this &lt;a href="https://www.facility9.com/"&gt;for his blog&lt;/a&gt; a while back? Uh, yeah, I thought of Chrissy first and my partner second. :woman-shrugging: Is that weird?&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/peschkaj"&gt;Jeremiah&lt;/a&gt; explained that he had fully converted his site up front (like Chrissy recommends). He is using &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; with the &lt;a href="https://themes.gohugo.io/Mainroad/"&gt;Mainroad theme&lt;/a&gt; and deploying to an Azure Static Web App. He recommended this approach and said that his experience now is good. But he also mentioned that the tooling he used to convert his posts wasn&amp;rsquo;t terrific and that he&amp;rsquo;d look for another alternative for getting WordPress content into Markdown.&lt;/p&gt;
&lt;p&gt;Coincidentally, &lt;a href="https://twitter.com/justinjbird7"&gt;Justin Bird&lt;/a&gt; mentioned on Twitter that he also moved to Hugo for his site. He &lt;a href="https://twitter.com/justinjbird7/status/1385645367962701825"&gt;said&lt;/a&gt; that he had used &lt;a href="https://github.com/lonekorean/WordPress-export-to-markdown"&gt;lonekorean&amp;rsquo;s WordPress-export-to-markdown project&lt;/a&gt; to convert his content.&lt;/p&gt;
&lt;p&gt;Together, this was all enough to give me a good starting point, so I dove right in.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In other words, I didn&amp;rsquo;t do an exhaustive comparison of static web generators and hosts. From what I&amp;rsquo;ve read, there are multiple great choices here. I&amp;rsquo;m already interested to try &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; and &lt;a href="https://www.netlify.com/pricing/"&gt;Netlify&lt;/a&gt; in future projects, perhaps.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="overview-of-my-static-site-setup"&gt;Overview of My Static Site Setup&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve alluded to a lot of this so far, but here&amp;rsquo;s a summary of all the tooling and services I am using for this site, along with cost considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LittleKendra.com is now an &lt;a href="https://azure.microsoft.com/en-gb/services/app-service/static/"&gt;Azure Static Web App&lt;/a&gt;. This is currently in preview and it&amp;rsquo;s totally free, but there may be a cost for this in the future. (Update May 18 2021: &lt;a href="https://kendralittle.com/2021/05/18/azure-static-sites-are-now-generally-available/"&gt;Azure Static Sites are now Generally Available with a free tier&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;My DNS is hosted by &lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt;, which is also proxying traffic. This is free.&lt;/li&gt;
&lt;li&gt;I use &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; as my static site generator with the &lt;a href="https://themes.gohugo.io/Mainroad/"&gt;Mainroad theme&lt;/a&gt;. This is all free.&lt;/li&gt;
&lt;li&gt;My code is in a private &lt;a href="https://github.com/"&gt;GitHub repo&lt;/a&gt;. That&amp;rsquo;s free.&lt;/li&gt;
&lt;li&gt;I use &lt;a href="https://code.visualstudio.com/"&gt;VSCode&lt;/a&gt; to author changes for my Hugo project, commit to Git, and push up to GitHub. VSCode is free.&lt;/li&gt;
&lt;li&gt;When I push new commits to my GitHub repo, a GitHub action runs to automatically build my code. If successful it deploys to my Azure Static Site. A good amount of &lt;a href="https://docs.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/about-billing-for-github-actions"&gt;GitHub Action usage is free&lt;/a&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here are the third party integrations I&amp;rsquo;m using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;m using &lt;a href="https://tinyletter.com/"&gt;TinyLetter&lt;/a&gt; to support people who want emails for blog posts (see below for details). This is free.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve embedded a &lt;strong&gt;Google Form&lt;/strong&gt; in a simple contact page for people who want to send me a message (see below for details). This is free.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m using &lt;strong&gt;the GitHub issues API and a public repo&lt;/strong&gt; for blog post comments (see below for details).This is free.&lt;/li&gt;
&lt;li&gt;I have a large amount of &lt;strong&gt;YouTube videos&lt;/strong&gt; which are embedded throughout the site via &lt;a href="https://gohugo.io/content-management/shortcodes/"&gt;Hugo shortcodes&lt;/a&gt;. Also free!&lt;/li&gt;
&lt;li&gt;I also have a few &lt;a href="https://gist.github.com/"&gt;GitHub Gists&lt;/a&gt; which are embedded throughout the site using Hugo shortcodes. (For shorter code samples, these are in the posts themselves and formatted via Markdown, no extra functionality needed.) Totally free.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve set up some &lt;a href="https://ifttt.com/home"&gt;ifttt applets&lt;/a&gt; to see new entries in the RSS feed. One automatically tweets while the other sends the info to my free &lt;a href="https://buffer.com/"&gt;Buffer account&lt;/a&gt;, which will automatically post the info to LinkedIn. Free.&lt;/li&gt;
&lt;li&gt;Giphy hosts some animated gifs which I created as short demonstrations for some posts. These are embedded simply as images. (More info on this below.) Free as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-conversion-process"&gt;The Conversion Process&lt;/h2&gt;
&lt;h3 id="set-up-my-azure-static-web-app-my-hugo-project-and-hook-up-publishing"&gt;Set Up My Azure Static Web App, My Hugo Project, and Hook Up Publishing&lt;/h3&gt;
&lt;p&gt;I began by following the steps outlined in this excellent &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/publish-hugo"&gt;Tutorial: Publish a Hugo site to an Azure Static Web Apps Preview&lt;/a&gt;. This walked me through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating my hugo project&lt;/li&gt;
&lt;li&gt;Adding a theme (this is installed as a git submodule)&lt;/li&gt;
&lt;li&gt;Setting up my Azure Static Web App in the Azure Portal&lt;/li&gt;
&lt;li&gt;Deploying my Hugo app to my Azure Static Web&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I carried all these steps in VSCode, the Azure Portal, and the GitHub web interface. This was all really accessible &amp;ndash; the steps even automatically created my GitHub Action which does the publishing! :star:&lt;/p&gt;
&lt;p&gt;Your Azure Static Web App is created with a default name. This enabled me to keep working on my project for a while and convert my existing content, then finally redirect my domain name when I felt ready to do so.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t have existing blog content to migrate, at this point you can just register a domain name, point it at the static site, and you&amp;rsquo;re off to the races!&lt;/p&gt;
&lt;h3 id="convert-my-wordpress-content-into-markdown-and-copy-the-files-into-my-hugo-project"&gt;Convert My WordPress Content Into Markdown and Copy the Files Into My Hugo Project&lt;/h3&gt;
&lt;p&gt;I used &lt;a href="https://github.com/lonekorean/WordPress-export-to-markdown"&gt;lonekorean&amp;rsquo;s WordPress-export-to-markdown project&lt;/a&gt; to do this conversion, as &lt;a href="https://twitter.com/justinjbird7"&gt;Justin Bird&lt;/a&gt; recommended. I had a good experience with this script.&lt;/p&gt;
&lt;p&gt;The instructions for the script guided me through this basic process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installed Node.js&lt;/li&gt;
&lt;li&gt;Exported &amp;ldquo;All content&amp;rdquo; from WordPress &amp;ndash; this generates an XML file you save locally&lt;/li&gt;
&lt;li&gt;Cloned down the &lt;a href="https://github.com/lonekorean/WordPress-export-to-markdown"&gt;WordPress-export-to-markdown&lt;/a&gt; script from GitHub&lt;/li&gt;
&lt;li&gt;Initiated the wizard from the command line and stepped through it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;During the conversion process, the script will go to your live WordPress site and save off images referenced in your posts. You can throttle the image downloads if you hit errors. I found that it did a great job in general of grabbing my images. It consistently failed on images which I&amp;rsquo;d imported from a different WordPress site at some point, for whatever reason, though. It was a small enough amount that I cleaned these up manually when I &amp;ldquo;groomed&amp;rdquo; my posts.&lt;/p&gt;
&lt;p&gt;I ran through the export process a few times and iteratively copied the files into my Hugo project and tested to make sure the generated files matched my old WordPress URL structure. It&amp;rsquo;s great that the script is flexible about this!&lt;/p&gt;
&lt;p&gt;In my case, all of my old blog URLs are in the format: kendralittle.com/yyyy/mm/dd/the-post-url/&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I didn&amp;rsquo;t use any year or month folders &amp;ndash; I put all my posts in a single folder and all my images in a single folder for simplicity&lt;/li&gt;
&lt;li&gt;The conversion script automatically put the post&amp;rsquo;s date, categories, and tags into the header of each markdown file&lt;/li&gt;
&lt;li&gt;I used the Hugo setting below to structure the URL format for my blog posts &amp;ndash; this picks up the date from the markdown file&amp;rsquo;s header and uses it in the URL structure for the published post&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[Permalinks]
posts = &amp;#34;/:year/:month/:day/:filename&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;My basic folder structure in Hugo (excluding my courses, more on that later) looks like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;.
├── content
| ├── posts
| | ├── a-post-title.md // &amp;lt;- https://www.kendralittle.com/1995/01/29/a-post-title/
| | └── i-wrote-this-too.md // &amp;lt;- https://www.kendralittle.com/2010/10/01/i-wrote-this-too/
| | └── {etc} // &amp;lt;- ~500 files total (one per post)
| └── about-kendra-little.md // &amp;lt;- https://www.kendralittle.com/about-kendra-little
| └── {etc} // &amp;lt;- I just have a few pages, no biggie
├── static
| └── images // &amp;lt;- All images
└── themes\Mainroad // &amp;lt;- This is the theme, which is a git submodule&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="test-how-everything-looks-locally"&gt;Test How Everything Looks Locally&lt;/h3&gt;
&lt;p&gt;One thing which I love love love about my static site is that I can do loads of work locally. All I need to do is run this command line in my project:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;hugo server&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This starts up a local webserver at http://localhost:1313/, which I can load in a browser and see exactly how my site looks now.&lt;/p&gt;
&lt;p&gt;And even better, every time I save a change to a file in my Hugo project, it rebuilds and the change is immediately visible on the webserver. And it&amp;rsquo;s :boom: &lt;strong&gt;FAST&lt;/strong&gt; :boom:. Having this super-fast local build and deploy made working on the conversion process really fun for me. I got to see things transform right before my eyes.&lt;/p&gt;
&lt;h3 id="groom-my-converted-content-keep-testing-locally-and-periodically-push-to-github"&gt;Groom My Converted Content, Keep Testing Locally, and Periodically Push to GitHub&lt;/h3&gt;
&lt;p&gt;No conversion script will be perfect for every use case. I used a combination of manual editing and &amp;ldquo;find and replace in files&amp;rdquo; functionality in VSCode (at times with regular expressions), to get my content into a shape which I like.&lt;/p&gt;
&lt;p&gt;Things which I fixed up include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replacing YouTube links with &lt;a href="https://gohugo.io/content-management/shortcodes/"&gt;Hugo shortcodes&lt;/a&gt;. I had at least three different styles of YouTube links and embedding styles in my old posts so this took a little work.&lt;/li&gt;
&lt;li&gt;Fixing up code samples in blog posts. I have a &lt;em&gt;lot&lt;/em&gt; of posts with SQL scripts which had been formatted in WordPress by at least three different plugins over the years. These are now very simply styled in markdown. This was probably the most time consuming thing for me to fix given the amount of code I had, but it was very satisfying.&lt;/li&gt;
&lt;li&gt;I had a few tables in posts which needed to be converted into markdown. I still had my old site available so this was just a matter of finding the posts by searching, loading up the old page, and using an online converter from HTML to markdown to generate the code.&lt;/li&gt;
&lt;li&gt;Identifying those images I had which didn&amp;rsquo;t get converted and replacing them as needed. Often these had a strange issue with links to a site which no longer exists being wrapped around them which needed cleaning &amp;ndash; almost certainly a remnant from having exported/imported them between WordPress sites before.&lt;/li&gt;
&lt;li&gt;Cleaning up places where I had linked an image to the source file in WordPress (these links all fail now because the folder structure is different, and I&amp;rsquo;m not sure why I even used those links in the first place)&lt;/li&gt;
&lt;li&gt;I had some large animated GIFs in posts. I moved these into Giphy and embedded them in Hugo as an image using the source URL from Giphy&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;![actual-elapsed-time-demo](https://media.giphy.com/media/VYWgrTTqR91933pz3f/source.gif)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Throughout the process of fixing things up, I constantly looked at my local webserver as I saved things.&lt;/p&gt;
&lt;p&gt;I also committed fairly frequently, and periodically pushed a batch of commits up to my GitHub repo to make sure that the build and deployment from that point was still working.&lt;/p&gt;
&lt;h3 id="move-my-free-training-courses-content-over"&gt;Move My Free Training Courses Content Over&lt;/h3&gt;
&lt;p&gt;After working with Hugo for a little while, I became ready to learn how to create a page structure alongside the blog to hold my courses and lessons.&lt;/p&gt;
&lt;p&gt;I had used a plugin to manage my courses in WordPress, and happily the &lt;a href="https://github.com/lonekorean/WordPress-export-to-markdown"&gt;WordPress-export-to-markdown&lt;/a&gt; script did convert markdown pages for all my courses and lessons. I just needed to figure out how to get these to display in some coherent fashion without manually having to add a lot of links to list out lessons for each post and navigate between them&amp;ndash; and ideally not change &lt;em&gt;too&lt;/em&gt; many URLs.&lt;/p&gt;
&lt;p&gt;It turns out that Hugo is very much suited to helping build out content like a &amp;ldquo;courses&amp;rdquo; structure with lessons. The main things I needed to learn about were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gohugo.io/content-management/page-bundles/"&gt;Page bundles in Hugo&lt;/a&gt; - Branch bundles allow me to have a main course page in which all the lesson pages are auto-magically linked into the parent course page in order.&lt;/li&gt;
&lt;li&gt;Taxonomies in Hugo enabled me to create a custom taxonomy for course categories, and drive navigation that way. There&amp;rsquo;s lots of documentation, but I found &lt;a href="https://www.jakewiesler.com/blog/hugo-taxonomies"&gt;this post by Jake Wiesler&lt;/a&gt; really helpful in getting me going.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gohugo.io/templates/"&gt;Templates&lt;/a&gt; to customize the look and feel of different pages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I did a lot of searching and employed a great deal of trial and error, but having a really fast and convenient local build and webserver experience made this fun to work out.&lt;/p&gt;
&lt;h3 id="re-point-dns-and-go-live"&gt;Re-Point DNS and Go Live&lt;/h3&gt;
&lt;p&gt;My old site&amp;rsquo;s performance was so bad that I probably should have cut over nearly right away and just put a note on the new site that I was working on cleaning things up. But I was excited enough about what I was building that I wanted it to be a certain level of &amp;ldquo;done&amp;rdquo; before I showed it to people.&lt;/p&gt;
&lt;p&gt;The process of cutting over is relatively simple, but I learned some important things about how to do this with an Azure Static Web App.&lt;/p&gt;
&lt;p&gt;Microsoft has provided good documentation on how to &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/custom-domain"&gt;setup a custom domain in Azure Static Web Apps Preview&lt;/a&gt;. Follow this, but note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure Static Web Apps only support mapping a subdomain while in Preview. In other words, I could use &lt;a href="https://www.littlekendra.com"&gt;https://www.littlekendra.com&lt;/a&gt;. The Preview does not support using a root domain like &lt;a href="https://littlekendra.com"&gt;https://littlekendra.com&lt;/a&gt; (but it sounds like this is coming later). &amp;lt;&amp;ndash; Update May 18 2021: &lt;a href="https://kendralittle.com/2021/05/18/azure-static-sites-are-now-generally-available/"&gt;root domains are now available&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re not a DNS wizard (and I am not), this can be confusing to configure. For simplicity, I pointed my nameservers to &lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt; and used their tooling to configure my DNS. In my experience they do a good job simplifying DNS management on their free plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are using Cloudflare, follow the steps in the documentation above to configure CNAMEs, but also know&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is a step in the Azure portal setup where it needs to verify the CNAME. For this to work, you need to have the CNAMEs set up in cloudflare set to &amp;ldquo;DNS only&amp;rdquo;. After the verification is complete you may change them to proxying traffic.&lt;/li&gt;
&lt;li&gt;I needed to go to &amp;ldquo;Rules&amp;rdquo; and create a Page Rule to handle existing links to pages at the root domain and send them to the www version. Here is the rule for my site:
&lt;ul&gt;
&lt;li&gt;If the url matches: &lt;code&gt;kendralittle.com/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then the settings are:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Forwarding URL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;301 - Permanent Redirect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://www.kendralittle.com/$1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DNS takes time to propagate, and in this case waiting was the hardest part. I was so excited to go live with my revamped little site!&lt;/p&gt;
&lt;h2 id="tips-and-tricks-for-setting-up-a-blog-with-hugo"&gt;Tips and Tricks for Setting Up a Blog With Hugo&lt;/h2&gt;
&lt;p&gt;Here are some highlights of things I&amp;rsquo;ve learned and resources I&amp;rsquo;ve used while configuring my new Hugo site with the Mainroad theme. I found that there&amp;rsquo;s a really great community out there and that I could solve most of my problems with searching and testing out different options.&lt;/p&gt;
&lt;h3 id="mainroad-theme"&gt;Mainroad Theme&lt;/h3&gt;
&lt;p&gt;There are only two things I&amp;rsquo;ve found which I couldn&amp;rsquo;t easily override or modify outside of the Mainroad theme submodule. I&amp;rsquo;ve worked around both of these by forking the &lt;a href="https://github.com/Vimux/Mainroad"&gt;Mainroad repo in GitHub&lt;/a&gt; and making the forked repo my sub-project. This allowed me to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Control thumbnail display.&lt;/strong&gt; I hate it when the post&amp;rsquo;s thumbnail image is automatically displayed at the top of a blog post &amp;ndash; I&amp;rsquo;ll add it in if I want! &lt;a href="https://github.com/Vimux/Mainroad/pull/175/files"&gt;I copied the code for this from an existing PR on the Mainroad theme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replace the default site favicon.&lt;/strong&gt; This appears to simply not have been made easily configurable but it&amp;rsquo;s easy to replace the file in my forked copy of the Mainroad repo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="general-styling"&gt;General Styling&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;I use a lot of right aligned floating images.&lt;/strong&gt; I couldn&amp;rsquo;t find a native way to do this, but used this &lt;a href="https://discourse.gohugo.io/t/handling-images-size-aligning/1940/2"&gt;undocumented cheat in my markdown code with a bit of css&lt;/a&gt; to make it work.
&lt;ul&gt;
&lt;li&gt;The Mainroad theme has an option to configure a location to place your own css file to override the theme&amp;rsquo;s default rules, so this was pretty simple.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not all themes support nested menus.&lt;/strong&gt; Mainroad is one of the themes that doesn&amp;rsquo;t. I used this post &lt;a href="https://codingnconcepts.com/hugo/nested-menu-hugo/"&gt;Add Sub Menu in Hugo Website by Coding N Concepts&lt;/a&gt; to implement a sub-menu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Social share icons on blog posts.&lt;/strong&gt; I used another article from &lt;a href="https://codingnconcepts.com/hugo/social-icons-hugo/"&gt;Coding N Concepts for this&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="contact-me-form"&gt;Contact Me Form&lt;/h3&gt;
&lt;p&gt;I spent a lot of time finding hard ways to do this before finding an incredibly easy way to do it. The easy way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a Google form with required fields for email address, name, and message (free with any google account)&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://gist.github.com/Miouyouyou/7515ff58f4891d1957eb13e20f429a9f"&gt;custom shortcode that wraps the form in an iFrame&lt;/a&gt; in a Hugo page.&lt;/li&gt;
&lt;li&gt;Call the shortcode from a Hugo page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s absolutely possible that trolls or bots could strike and hit the form with a lot of garbage data &amp;ndash; but this is honestly a risk for any contact form solution. If that happens it&amp;rsquo;s really easy for me to just delete the form. For a 1.0 this is just a really easy way to start.&lt;/p&gt;
&lt;h3 id="blog-post-comments"&gt;Blog Post Comments&lt;/h3&gt;
&lt;p&gt;A lot of people seem to use Disqus for their comments. You can sync your older comments from WordPress into Disqus if you want an automated way to carry those over.&lt;/p&gt;
&lt;p&gt;As a woman on the internet, I have had a mixed experience with comments. Some very positive, some&amp;hellip; not.&lt;/p&gt;
&lt;p&gt;I decided that for now I am going to use a loosely integrated system with comments &lt;a href="https://retifrav.github.io/blog/2019/04/19/github-comments-hugo/"&gt;implemented via GitHub issues, as described here&lt;/a&gt;. I migrated over comments for some of my most popular posts according to Google Analytics, but generally didn&amp;rsquo;t worry about the rest. This means that comments are effectively closed on a lot of my older posts and, well, I&amp;rsquo;m totally fine with that.&lt;/p&gt;
&lt;p&gt;In the future, I may look at implementing GiTalk. &lt;a href="https://twitter.com/justinjbird7"&gt;Justin Bird&lt;/a&gt; has implemented them &lt;a href="https://www.justinjbird.me/2021/hugo-content-organisation/"&gt;here&lt;/a&gt; and they take using GitHub issues for comments to another level.&lt;/p&gt;
&lt;h3 id="rss-and-blog-post-subscriptions"&gt;RSS and Blog Post Subscriptions&lt;/h3&gt;
&lt;p&gt;Some folks like to subscribe to blog posts &amp;ndash; the two popular choices seem to be by RSS feed and by email.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth setting up both, if you have time. The email solution will depend on your RSS feed, so do that first.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hugo provides native RSS feed capabilities, but it wasn&amp;rsquo;t enabled by default in my theme. I just needed to figure out what to put in my project&amp;rsquo;s config.toml file to make it work.
&lt;ul&gt;
&lt;li&gt;This post on &lt;a href="https://codingnconcepts.com/hugo/custom-rss-feed-hugo/"&gt;custom RSS feeds in Hugo from Coding N Concepts&lt;/a&gt; helped.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve set up a &lt;a href="https://tinyletter.com/littlekendra"&gt;Tiny Letter account&lt;/a&gt; to allow people to subscribe to blog posts. This is free.
&lt;ul&gt;
&lt;li&gt;I use Zapier to automatically communicate to Tiny Letter when a new blog post appears in my RSS feed.&lt;a href="https://backendology.com/2018/08/31/hugo-newsletter/"&gt;This backendology post steps through how to configure this&lt;/a&gt;. Zapier has a free plan which should meet most people&amp;rsquo;s needs for this use case.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="closing-thoughts"&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve had a great deal of fun working on this project. I&amp;rsquo;m more excited about blogging than I&amp;rsquo;ve been in a long time, and I&amp;rsquo;m looking forward to finding little ways to tweak and improve this site over time as well.&lt;/p&gt;
&lt;p&gt;In a way, I guess this is all thanks to that terrible WordPress host. They ended up really improving my website, even if it was by convincing me to abandon WordPress and use static site generators for most of my personal website uses in the future. :woman-shrugging:&lt;/p&gt;
&lt;p&gt;More genuine thanks go to the folks who helped me figure out this whole static site thing &amp;ndash; everyone whose articles I&amp;rsquo;ve linked to above, plus:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My partner &lt;a href="https://twitter.com/peschkaj"&gt;Jeremiah&lt;/a&gt; - for helping me curse at Git until it did what I wanted and letting me copy his DNS setup and forwarding rules&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/justinjbird7"&gt;Justin Bird&lt;/a&gt; - for all the tips and tricks&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/cl"&gt;Chrissy LeMaire&lt;/a&gt; for sharing her lessons learned&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Help Me Not Be Selected to Speak at the Dativerse Virtual Conference</title><link>https://kendralittle.com/2021/04/22/help-me-not-be-selected-to-speak-at-the-dativerse-virtual-conference/</link><pubDate>Thu, 22 Apr 2021 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/04/22/help-me-not-be-selected-to-speak-at-the-dativerse-virtual-conference/</guid><description>&lt;p&gt;A call for speakers is open for the very first edition of the Dativerse conference, which will be held on August 13, 2021: &lt;a href="http://dativerse.io/"&gt;http://dativerse.io/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="an-overview-of-the-event-from-the-dativerse-call-for-speakers"&gt;An Overview of the Event From the Dativerse Call for Speakers&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-22-04-2021_16-17-24.jpg"
alt="Screenshot of multicolored smoke clouds" width="230"&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Dativerse is a new event in the Microsoft Data Platform space. Our session selection criterias are easy&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your session must be related to the Microsoft Data Platform&lt;/li&gt;
&lt;li&gt;You contribute to the diversity of the Microsoft Data Platform
We try to elevate those that are usually underrepresented at conferences due to their race, gender, sexual orientation, location or any other reason.
We aim to create a safe environment for everyone and welcome seasoned speakers and newcomers alike. Should you require a mentor, we will make sure you will get all the help you&amp;rsquo;ll need to deliver your session!&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve submitted a session, but I&amp;rsquo;ve mostly done that because I want LOTS of people to submit sessions. I can now say, &amp;ldquo;I submitted a session and I think lots of others should, too.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="why-id-love-for-many-others-to-submit"&gt;Why I&amp;rsquo;d Love for Many Others to Submit&lt;/h2&gt;
&lt;p&gt;I am a white, cisgender woman who is married to a man. I&amp;rsquo;m also at a point in my career where I&amp;rsquo;ve established a strong network. While we have a long way to go to reach gender equality in tech, I also recognize that I am relatively privileged due to my race, orientation, social background, and my connections. I feel it&amp;rsquo;s important for me at this time in my life to get better at helping others rise up.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also found in my life that the most exciting and productive teams I&amp;rsquo;ve worked on have had team members from a very diverse mix of backgrounds, experiences, and preferences. I strongly believe that having a more diverse, open, and welcoming community is good for everyone who is part of that community.&lt;/p&gt;
&lt;h2 id="help-spread-the-word-far-and-wide-about-this-event"&gt;Help Spread the Word Far and Wide About This Event&lt;/h2&gt;
&lt;p&gt;Please encourage others from a rainbow of backgrounds to apply. My hope is that there will be so many sessions submitted from people of diverse backgrounds that my session is not chosen, and I can support the event in another capacity.&lt;/p&gt;
&lt;p&gt;Please share and encourage others see if &lt;a href="https://sessionize.com/dativerse"&gt;Dativerse&lt;/a&gt; is a good fit for them at this point in their career.&lt;/p&gt;</description></item><item><title>Free Virtual Event: Mental Health and Awareness Day on May 7th</title><link>https://kendralittle.com/2021/04/21/free-virtual-event-mental-health-and-awareness-day-on-may-7th/</link><pubDate>Wed, 21 Apr 2021 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2021/04/21/free-virtual-event-mental-health-and-awareness-day-on-may-7th/</guid><description>&lt;p&gt;I&amp;rsquo;ll be giving a 10 minute lightning talk at the upcoming &lt;a href="https://www.meetup.com/data-platform-wit/events/277595027"&gt;Mental Health and Wellness day event&lt;/a&gt; on May 7, 2021, hosted by the Data Platform WIT group.&lt;/p&gt;
&lt;h2 id="my-session-maintaining-balance-while-re-training-in-a-new-professional-area"&gt;My Session: &amp;ldquo;Maintaining Balance While Re-Training in a New Professional Area&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;It begins at 1:10 PM GMT / 9:10 AM Eastern.
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-21-04-2021_11-55-32.jpg"
alt="Screenshot or image related to Mental Health and Awareness Day event"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;I am inspired to talk on this topic because I&amp;rsquo;ve shifted my career a few times:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From Tech Support to Database Administrator&lt;/li&gt;
&lt;li&gt;Then to consultant and small business owner&lt;/li&gt;
&lt;li&gt;Then to Developer Advocate&lt;/li&gt;
&lt;li&gt;And now I&amp;rsquo;ve moved into a Product Manager role&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These kinds of career shifts are common and healthy in the modern workplace. Moving into a new role often requires quite a bit of new learning at a fast pace, though, and for some of us this can be quite stressful. I&amp;rsquo;ll share the top lessons that I&amp;rsquo;ve learned to set myself up for success and protect my health when taking on a new professional challenge.&lt;/p&gt;
&lt;h2 id="cant-join-live"&gt;Can&amp;rsquo;t Join Live?&lt;/h2&gt;
&lt;p&gt;I believe my session will be recorded and made available on YouTube afterwards if the technical stars align.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s many more great sessions in the lineup&amp;ndash; more info over on the &lt;a href="https://www.meetup.com/data-platform-wit/events/277595027"&gt;Mental Health and Wellness day event&lt;/a&gt; page.&lt;/p&gt;</description></item><item><title>Ten Ideas to Improve Online Tech Conferences</title><link>https://kendralittle.com/2020/11/18/ten-ideas-to-improve-online-tech-conferences/</link><pubDate>Wed, 18 Nov 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/11/18/ten-ideas-to-improve-online-tech-conferences/</guid><description>&lt;p&gt;Amid the global pandemic, online tech conferences have had a natural surge in popularity. I&amp;rsquo;ve attended quite a few of these in 2020 across several technical areas (database tech, DevOps, privacy, tech research). The conferences have been both large and small, both free and paid, and have been held across a few different regions and time zones.&lt;/p&gt;
&lt;p&gt;Many things have gone well. Organizations who are used to doing in-person events have worked hard to quickly adapt to online platforms, and I&amp;rsquo;ve seen some fantastic content. This is terrific!&lt;/p&gt;
&lt;p&gt;But there are a few critical things that &lt;em&gt;haven&amp;rsquo;t&lt;/em&gt; adapted well in the transition to online events. I&amp;rsquo;ve seen some major problems occur consistently across &lt;em&gt;all&lt;/em&gt; these tech conferences. This isn&amp;rsquo;t due to laziness or lack of trying &amp;ndash; it&amp;rsquo;s simply that some patterns that work at physical events don&amp;rsquo;t work well at online events.&lt;/p&gt;
&lt;p&gt;We are learning as we go.&lt;/p&gt;
&lt;p&gt;With creativity we can massively improve the experience of online events &amp;ndash; and that&amp;rsquo;s really worth doing! Please help brainstorm and share your own ideas about how to make online conferences more awesome.&lt;/p&gt;
&lt;h2 id="why-it-matters-if-you-care-about-inclusivity-improving-online-conferences-is-very-important"&gt;Why It Matters: If You Care About Inclusivity, Improving Online Conferences Is Very Important&lt;/h2&gt;
&lt;p&gt;My favorite thing about online conferences is that they are generally &lt;em&gt;far&lt;/em&gt; more accessible and open than in-person events.&lt;/p&gt;
&lt;p&gt;Travel and hotel costs for in-person events are often significant, and only those who are already in quite Senior roles typically have the benefit of these being paid by their employer. Ticket prices for in-person conferences are also generally higher, and less privileged community members similarly have a more difficult time getting these funded, often needing to pay out of their own pockets.&lt;/p&gt;
&lt;p&gt;I also believe that low cost and free online events may create more open communities, as there is relatively low risk for someone new to the community to try out the event for a short time. Online spaces may feel safer for members of marginalized groups in terms of testing the waters to find out what a community is all about. This can result into bringing fresh ideas and many new people into the community, both in terms of those who are new to working in tech and in terms of those who specialize in other areas.&lt;/p&gt;
&lt;p&gt;For these reasons, even if we are able to get back to in-person events quite soon, I have hopes that online tech events will continue to be a stronger presence than they were prior to the COVID-19 pandemic.&lt;/p&gt;
&lt;p&gt;To do this, we need to solve some important problems about funding community and professional conferences, as well as improve the participant experience.&lt;/p&gt;
&lt;h2 id="problem-1-sponsors-are-isolated-because-expo-halls-dont-work-online"&gt;Problem 1: Sponsors Are Isolated Because Expo Halls Don&amp;rsquo;t Work Online&lt;/h2&gt;
&lt;p&gt;Most community and professional tech events, both free and paid, rely on sponsors to lower costs for attendees. Platforms for online events and staff to help organize and carry out the event cost real money, so this is still incredibly relevant for online events.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve seen event after event attempt to replicate the &amp;lsquo;Vendor Expo Hall&amp;rsquo; of an in-person tech conference. And at event after event, I have seen minimal to no engagement &amp;ndash; I&amp;rsquo;ve yet to see or hear about &amp;lsquo;Vendor Booths&amp;rsquo; working in an online format. After all, there&amp;rsquo;s no good online way to replicate the ways that events have made the Vendor Expo Hall more fun at physical events: free toys and swag, tasty food and drinks, games and magicians and entertainment which can take place right next to personal, real-world conversations.&lt;/p&gt;
&lt;p&gt;Here are some things I&amp;rsquo;ve seen which didn&amp;rsquo;t work well. If you&amp;rsquo;re going to try them, change them up a bit to avoid known pitfalls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vendor happy hours at the very end of the day&lt;/strong&gt; - an in-person happy hour sponsored by a vendor with refreshments served works well sometimes at physical events &amp;ndash; often at these, attendees prefer to relax with others rather than return to an empty hotel room or sit in traffic during a busy commute time. At virtual events, everyone has screen fatigue, there&amp;rsquo;s no refreshments, and only one person can talk at a time. Plus, attendees would probably rather be spending the evening with their families.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idea&lt;/strong&gt;: work more of the events suggested below into the &amp;lsquo;daytime&amp;rsquo; conference schedule itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vendor lunchtime hours when you provide competing entertainment&lt;/strong&gt; - It&amp;rsquo;s great to provide lunchtime entertainment. But if you&amp;rsquo;re not otherwise working sponsors into your event schedule, don&amp;rsquo;t ask them to compete with paid entertainment at lunch.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idea&lt;/strong&gt;: bring them &lt;em&gt;into&lt;/em&gt; the lunch entertainment in some ways (and also work them into the event schedule in other ways).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Visit a vendor booth&amp;rdquo; scavenger hunts -&lt;/strong&gt; I&amp;rsquo;ve seen some conferences do simple code scavenger hunts to try to keep the sponsorship &amp;ldquo;exhibit&amp;rdquo; area in their platform from being a dead zone. I&amp;rsquo;ve yet to see or hear about this working, unfortunately. Some attendees snag the codes and leave, many ignore it altogether.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idea&lt;/strong&gt;: make the contests more about meaningful interactions. More on this below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="problem-2-conference-participants-have-a-hard-time-making-meaningful-connections"&gt;Problem 2: Conference Participants Have a Hard Time Making Meaningful Connections&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been part of conferences which have worked on building engagement in quite a few ways, which is great &amp;ndash; but none have been great at helping participants create meaningful connections with speakers, each other, and sponsors. Here&amp;rsquo;s what I&amp;rsquo;ve seen tried:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Chat roulette&amp;rdquo; style platform features&lt;/strong&gt;: Several online conference platforms have decided that attendees want to experience the most stressful parts of online dating in a technical conference, and offer people the chance to be paired up with a random stranger for a few minutes on a video call. I haven&amp;rsquo;t seen this work well: attendees don&amp;rsquo;t seem tempted to join, and the platforms often seem to be error prone and not great at managing this.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idea&lt;/strong&gt;: I have some suggestions for regular small-group gatherings and interactive workshops below &amp;ndash; and there are ways to work sponsors into this as well!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slack/Discord chat accompanyments&lt;/strong&gt;: Several online conferences have offered (or attendees have created) social spaces where people can chat along with the event. While I think these can be a great back-channel for some and these can fill some needs for Q&amp;amp;A, for many these are overwhelming. They also become insanely busy very quickly if the conference drives a lot of people to them. So while they fill some needs, they don&amp;rsquo;t help most people feel like they made meaningful connections.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idea&lt;/strong&gt;: keep evolving this model, but don&amp;rsquo;t rely on it for meaningful engagement.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Presenter Q&amp;amp;A during a &amp;rsquo;live replay&amp;rsquo; of a pre-recorded session&lt;/strong&gt;: I personally really like this model as a presenter &amp;ndash; it&amp;rsquo;s nice to know my session is safely pre-recorded and to be present to live chat with attendees in a text box. However, for many attendees it is hard to follow both a live chat window and a pre-recorded session that goes on simultaneously! While one may get a question answered, one leaves the session feeling a bit frazzled &amp;ndash; rather the opposite of having a meaningful connection.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Continue leveraging pre-recorded sessions if that helps you ensure a more consistent experience for your attendees, but allow time in your schedule for live Q&amp;amp;A after the session with the presenter, ideally with a webcam. They can recap chat that happened in the session, answer new questions, and reflect on how their session connects with other sessions at the conference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Another lesson learned&lt;/strong&gt;: for your speakers, it&amp;rsquo;s critical to set expectations very early (such as in the call for sessions itself) about whether pre-recording will be needed, and what due dates and expectations you have for recording quality.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="problem-3-conference-participants-suffer-from-screen-exhaustion-and-painfully-long-days"&gt;Problem 3: Conference Participants Suffer From Screen Exhaustion and Painfully Long Days&lt;/h2&gt;
&lt;p&gt;Most conferences have kept similar time frames and flow of sessions as they&amp;rsquo;ve moved into online events. However, the attendee experience is different: there&amp;rsquo;s no physical movement between sessions. There&amp;rsquo;s no change of scenery. And it&amp;rsquo;s often even harder for participants to disconnect fully from their work: they end up checking emails frantically during breaks, in early mornings, and in evenings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ideas&lt;/strong&gt;: Mixing up &amp;ldquo;types&amp;rdquo; of sessions between more passive learning and interactive sessions will help a bit (but not do the whole job)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Experimenting with different &amp;ldquo;tempos&amp;rdquo; for online event days is important for conference organizers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Experiment with more partial-day events rather than only full-day sessions. Could an online platform even allow you to have an event across more than one week?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part of this is mindset for the organizers&lt;/strong&gt;: resist the urge to believe that the selling point of your conference is a relentless bombardment of information across multiple tracks. Focus on maximizing the value participants will take away instead, which means helping them absorb information and have some time away from the conference screen.&lt;/p&gt;
&lt;p&gt;Those are the three biggest problems I&amp;rsquo;ve seen.&lt;/p&gt;
&lt;p&gt;Now for the fun part: ideas on how to make this more sustainable, more rewarding for participants, and more awesome!&lt;/p&gt;
&lt;h2 id="ten-ideas-to-make-online-conferences-more-awesome"&gt;Ten Ideas to Make Online Conferences More Awesome&lt;/h2&gt;
&lt;p&gt;These are numbered, but not ranked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;More Birds-of-a-Feather Chats, and Work In Your Sponsors&lt;/strong&gt; - One thing I&amp;rsquo;ve seen that worked very well was mixing regular time periods into the conference schedule where conference attendees were invited to join live small-group discussions led by a moderator. Multiple discussions on different topics were live at each time. These were held in a format that allowed attendees to share webcams and microphones. Moderators came prepared with a list of questions and topics to spark the discussion.&lt;/p&gt;
&lt;p&gt;This helps attendees have time for more meaningful engagements. The difference in format between this and a more passive learning session provides a needed change of pace. And you also have the option of inviting your vendors to participate in these, particularly the topics which are related to their mission and areas of interest. (This doesn&amp;rsquo;t necessarily mean doing demos or selling products, but rather being part of the discussion.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Workshops, some Sponsored&lt;/strong&gt; - I&amp;rsquo;m not going to lie, workshops ain&amp;rsquo;t easy to do well, whether in-person or online. But these are absolutely worth experimenting on, as when they are great they are &lt;em&gt;amazing&lt;/em&gt; for your participants. Some notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Since this is hard, allow plenty of planning time, start with shorter workshops with fewer tech requirements, and do pilots first to find your groove. Build on your experience across subsequent events.&lt;/li&gt;
&lt;li&gt;A key to a good workshop is scoping and selecting the right topics. Don&amp;rsquo;t fall into the trap of thinking tech workshops need to be all about how an engineer performs a technical task while they follow along in a cloud environment: that&amp;rsquo;s super hard mode! Start with &amp;ldquo;softer&amp;rdquo; topics around professional development or making strategies to effect change in the modern work environment.&lt;/li&gt;
&lt;li&gt;I am personally a fan of the &lt;a href="https://ajsmart.com/ldj"&gt;Lightning Decision Jam workshop format&lt;/a&gt;, which can work well online with access to resources like &lt;a href="https://www.mural.co/"&gt;Mural&lt;/a&gt; . A great thing about this format is that it utilizes non-verbal communication effectively, and there&amp;rsquo;s a lot of folks who aren&amp;rsquo;t a fan of talking to a bunch of strangers in a video call. Find some formats you can suggest to your workshop organizers, but allow them to be creative.&lt;/li&gt;
&lt;li&gt;For effective workshops, you need a way to limit the number of people in the workshops, which may require pre-registration to pull off. It also helps to have some volunteers available to switch workshops and balance out the groups if you have some which are low on numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. Commercial Contests&lt;/strong&gt; - I know, especially for paid conferences, attendees may not love the idea of seeing sponsor commercials as part of the main conference track. But what if you gamified this for your sponsors, and added a contest for your attendees related to it? This could be &lt;em&gt;really fun&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep the commercials short - 90 seconds to 2 minutes&lt;/li&gt;
&lt;li&gt;Play the commercials live and reveal them throughout the conference, have an emcee announce them and reference the contest each time&lt;/li&gt;
&lt;li&gt;Have multiple categories people can vote on &amp;ndash; funniest, best production quality, most thought provoking, most educational, most charming, etc.&lt;/li&gt;
&lt;li&gt;Open the voting at a specific time in the conference once they&amp;rsquo;ve all been launched, have a YouTube channel where attendees can watch them again in case they missed any&lt;/li&gt;
&lt;li&gt;Encourage vendors to add a URL at the end of their video or to appear at the bottom of the screen the whole time for lead generation purposes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Prizes for Meaningful Engagement&lt;/strong&gt; - As I mentioned above, I&amp;rsquo;ve seen simple scavenger hunts fail miserably. Just &amp;ldquo;visiting&amp;rdquo; a vendor booth in an online world doesn&amp;rsquo;t make for engagement with the vendor. Why not change the contest up? Your conference platform needs to provide &lt;em&gt;some&lt;/em&gt; way of interacting with sponsors, whether it&amp;rsquo;s by chat room, video chat, or even email options. Ideas to hype throughout your conference to encourage engagement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Best question&amp;rdquo; contest&lt;/strong&gt;: allow each sponsor to nominate up to &lt;em&gt;N&lt;/em&gt; (whatever number is appropriate for your scale) people who asked the best questions for a prize draw. The winner draw can be done and announced at the end of the conference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sponsor trivia contest&lt;/strong&gt;: create a trivia game where all the questions are about your sponsors and how their offerings relate to your attendees and their pain points. Source the trivia facts from your sponsors ahead of time, and if you&amp;rsquo;re doing a booth leverage things in their written materials and live demos. Have good prizes! Emphasize how valuable it is for the conference for contestants to share their email addresses and pain points with sponsors (but have a way for them to specify their contact preferences clearly, as noted below). This is a great &amp;ldquo;late in your day&amp;rdquo; session option for near the close of your event. Platforms like &lt;a href="https://kahoot.it/"&gt;https://kahoot.it/&lt;/a&gt; can make the trivia fun. (Note: do some test runs and allow for latency between the game and your viewers.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus groups, with prizes for attending&lt;/strong&gt;: Have time slots for 20-30 minute focus group interviews run by your sponsors. Give a small prize (gift cards, stickers sent by mail, etc.) to attendees to who participate in at least &lt;em&gt;N&lt;/em&gt; number of focus groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5. Help Vendors Learn &lt;em&gt;and&lt;/em&gt; Create Leads&lt;/strong&gt; - Why would vendors want to sponsor community and professional events when they can run their own online events at a pretty low cost and gather all the leads they want? The answer is that vendors want to find new potential customers &lt;em&gt;and&lt;/em&gt; to learn about where customers are going in the marketplace.&lt;/p&gt;
&lt;p&gt;In other words, conferences can work to help vendors with both short term and longer term goals. Successful vendors understand that building their brand over time is important. They understand that learning about potential customers, their pain points, their perspectives, their goals, is key to their survival. Ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vendor surveys&lt;/strong&gt;: Offer options for vendors to link attendees to relatively short (5 minute) surveys asking attendees about their pain points, interests, goals, etc. A contest for attendees who complete surveys is a potential encouragement for this one if you have interest from a good amount of vendors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vendor focus groups&lt;/strong&gt;: See the &amp;ldquo;workshop&amp;rdquo; section above for more info on this. A focus group can feel more approachable / less intrusive for an attendee, as it&amp;rsquo;s clear that the point is to help the vendor by sharing experience and that the attendee may not necessarily be ready to buy a product.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lead generation is still important&lt;/strong&gt;. Don&amp;rsquo;t skip this! &lt;em&gt;Do&lt;/em&gt; still work on building and improving the ways in which you encourage attendees to share their contact information with vendors when it&amp;rsquo;s beneficial for both parties. But add value around that wherever you can.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Showcase free training resources from sponsors which employees can use after the event&lt;/strong&gt;: Many vendors have free online resources which can be very valuable for attendees (whether or not they are a customer of that vendor). This is everything from YouTube Channels to whitepapers to online courses. Ask your vendor if they have these, and showcase them for your conference participants in multiple ways throughout the conference &amp;ndash; be it on banner adds, downloadable lists of resources, short video clips on the main stage, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6. Ideas to Overcome &amp;ldquo;Awkward Chat Room&amp;rdquo; Experiences&lt;/strong&gt; - I know quite a few folks who &lt;em&gt;hate&lt;/em&gt; awkward silences in online meetings. It makes their skin crawl. I know others who feel very shy at speaking up in an online session. Others who can&amp;rsquo;t stand turning on webcams.&lt;/p&gt;
&lt;p&gt;And then there&amp;rsquo;s the problem of having 12 people in a video room, and everyone starts talking at once, then apologizing. There&amp;rsquo;s That Person who can&amp;rsquo;t help dominating the discussion. There&amp;rsquo;s so many ways that things can get awkward.&lt;/p&gt;
&lt;p&gt;And also, let&amp;rsquo;s face it, video calls get &lt;em&gt;super boring&lt;/em&gt; real fast these days. Ideas to make it more interesting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Provide non-verbal ways to participate&lt;/strong&gt;: Apps like &lt;a href="https://www.polleverywhere.com/"&gt;Poll Everywhere&lt;/a&gt; break up the monotony and allow people to give non-verbal feedback that is immediately visible to the group online (as long as the person hosting the polls/surveys are screen sharing).
&lt;ul&gt;
&lt;li&gt;Other apps like &lt;a href="https://www.mural.co/"&gt;Mural&lt;/a&gt; also provide ways to do this, but have fewer controls if you are worried about spammers or rogue feedback in more open events. (Poll Everywhere has some moderation abilities on free text style questions, and you can also stick to other question types if needed.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Breakout Rooms, if you can&lt;/strong&gt;: If you&amp;rsquo;ve got a larger group, apps like &lt;a href="https://support.zoom.us/hc/en-us/articles/206476093-Enabling-breakout-rooms"&gt;Zoom&lt;/a&gt; let you split folks into smaller breakout rooms for certain periods of time. This is useful for some workshop formats and focus groups.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plan a game or activity&lt;/strong&gt;: If you&amp;rsquo;re doing something like vendor chats or happy hours, I think a planned activity of some sort is really helpful. Relying on the guests who show up to provide the topics of conversation is often the cause of the awkwardness.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;7. Pre-Recorded Sessions, Live Q&amp;amp;A After&lt;/strong&gt; - Many conference organizers like to have some or all the sessions at an online event available in a recording ahead of time. This helps them ensure that the show will go on, no matter what technical problems ensue. (See my note above about the importance of mentioning your recording requirements when you do your call for speakers.)&lt;/p&gt;
&lt;p&gt;I understand the appeal of pre-recorded sessions at a very personal level, having had my home internet stop working completely on the first day of a three day conference recently. I was working off a series of not-great-bandwidth cellular devices until it was repaired by line crews outside my home EXACTLY as the conference ended on the last day. My sessions were 100% saved by the fact that I&amp;rsquo;d pre-recorded them.&lt;/p&gt;
&lt;p&gt;But as I mention above, it&amp;rsquo;s a huge challenge for attendees to multi-task and learn at the same time. I&amp;rsquo;ve yet to see a platform where a presenter could pause a pre-recorded session to handle a question live. Instead, chat and Q&amp;amp;A flows past while the session marches forward.&lt;/p&gt;
&lt;p&gt;Part of the solution longer term involves explaining this challenge to conference platforms, and asking them for ideas to solve it. In the meantime, adjust your session timings accordingly!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you want to do pre-recorded sessions in 40 minute timeslots, ask presenters to do 30 minute sessions and be available for the session and a live Q&amp;amp;A spot in the 10 minutes after the session.&lt;/li&gt;
&lt;li&gt;Allow webcam in the live period if you can.&lt;/li&gt;
&lt;li&gt;Encourage presenters to come prepared with a couple of things to discuss if Q&amp;amp;A is slow, such as how their session relates to others at the conference, how attendees can learn more, the most common misunderstandings on the topic, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;8. Shorter Days, Longer Events&lt;/strong&gt; - I know event organizers are used to going flat out for a few days and then wrapping everything up. That makes sense when people need to travel to attend your event. But the game is very different with online events, and it&amp;rsquo;s time to change tempos.&lt;/p&gt;
&lt;p&gt;In teaching online courses over the years prior to the pandemic, I learned that shorter sessions spread across more days helped attendees learn more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They were able to take care of the most urgent things in their workplace in the hours that they weren&amp;rsquo;t in class&lt;/li&gt;
&lt;li&gt;They were able to absorb things by spreading learning out over more time&lt;/li&gt;
&lt;li&gt;They were able to literally &amp;ldquo;sleep on things&amp;rdquo; &amp;ndash; several reported having woken up understanding something more clearly!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is going to be a big mindset change for organizers in terms of marketing. Conference organizers are used to advertising on being the &amp;ldquo;biggest&amp;rdquo; conference with the most concurrent sessions. But with this approach, attendees leave your event feeling burnt out and strangely lonely. Will that bring them back?&lt;/p&gt;
&lt;p&gt;A key part of improving attendee experience in online conferences will be experimentation with both session formats and conference timing. Think about how to help your attendees have the best experiences with new scheduling patterns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9. Plan Carefully for Multi-Timezone Events&lt;/strong&gt; - Timezones are hard, y&amp;rsquo;all. They&amp;rsquo;re hard when planning an event, and they&amp;rsquo;re hard when attending an event.&lt;/p&gt;
&lt;p&gt;If you are an event organizer and are evaluating an online platform, a critical thing to evaluate is how the platform presents times to people who may be watching from different timezones. How easy is it for people to understand when sessions begin and end? &lt;em&gt;It needs to be super easy.&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/timezone.png"
alt="Screenshot or diagram showing timezone information"&gt;
&lt;/figure&gt;
&lt;p&gt;Assume that the group of people who enjoy time zone math does not at all overlap with the group of people attending your event.&lt;/p&gt;
&lt;p&gt;Depending on what technology you have to work with, you may not have a &amp;ldquo;perfect&amp;rdquo; option as an organizer. But do your best to try to provide whatever workarounds you can to make your attendees from different time zones feel at home. And express how important this is to the people who make virtual event platforms, please. This is a courtesy your guests will notice!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10. Be Clear &amp;ndash; But Not Paranoid or Greedy &amp;ndash; About Vendor Sessions&lt;/strong&gt; - This is a funny one, because it&amp;rsquo;s more of an issue in some tech circles than in others. In both DevOps and Privacy themed conferences, it&amp;rsquo;s fairly normal for vendors to give sessions which feature how their products work. The sessions are typically clearly labeled so you know what you&amp;rsquo;re going to see. It&amp;rsquo;s not a big deal.&lt;/p&gt;
&lt;p&gt;This is a good model for others to embrace. Offer sponsoring vendors the chance to give sessions explaining how their solutions give value. Clearly label the sessions so that attendees know what to expect and can choose accordingly.&lt;/p&gt;
&lt;p&gt;This model actually works better in an online conference format than it does in an in-person one. Your sponsors will be highly aware of how easy it is to quietly and quickly leave an online session which is dull or generally unhelpful! There is none of the awkwardness of stepping through a row of people in a physical room to keep people there. The online format means that vendors need to bring relevance and value in these sessions, which is great for both attendees and conference organizers.&lt;/p&gt;
&lt;h2 id="this-is-just-the-beginning"&gt;This Is Just the Beginning&lt;/h2&gt;
&lt;p&gt;This is only ten ideas. There are many more! What we need is creativity.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d love to see tweets, blog posts, and LinkedIn articles about what you think will make online conferences more sustainable and better experiences.&lt;/p&gt;</description></item><item><title>Coping with the Pandemic (T-SQL Tuesday #132)</title><link>https://kendralittle.com/2020/11/10/coping-with-the-pandemic-t-sql-tuesday-132/</link><pubDate>Tue, 10 Nov 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/11/10/coping-with-the-pandemic-t-sql-tuesday-132/</guid><description>&lt;p&gt;This post is part of the monthly &lt;a href="http://tsqltuesday.com/"&gt;TSQLTuesday&lt;/a&gt; blog event. This month&amp;rsquo;s topic is from Taiob Ali.&lt;/p&gt;
&lt;p&gt;Taiob &lt;a href="https://sqlworldwide.com/t-sql-tuesday-132-how-are-you-coping-with-pandemic/"&gt;asks how are we coping amid the pandemic&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tsql2sday-logo.jpg"
alt="T-SQL Tuesday logo" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="i-have-two-thoughts-overall-about-how-well-im-coping"&gt;I Have Two Thoughts Overall About How Well I&amp;rsquo;m Coping&lt;/h2&gt;
&lt;p&gt;Thought 1: Wow this is rough.&lt;/p&gt;
&lt;p&gt;Thought 2: I am incredibly lucky and privileged, and it&amp;rsquo;s still rough.&lt;/p&gt;
&lt;h2 id="my-pandemic-story-started-with-an-intercontinental-move"&gt;My Pandemic Story Started With an Intercontinental Move&lt;/h2&gt;
&lt;p&gt;At the beginning of March 2020, I moved with my husband and two dogs from Portland, Oregon to Cambridge, England. The virus was in the news at that point, but we had no idea how it would spread and how the world would change.&lt;/p&gt;
&lt;p&gt;After nearly ten years of working at home, my intention in moving was that I&amp;rsquo;d begin to work from the Cambridge office for my employer, Redgate. I&amp;rsquo;d also periodically travel to visit customers in the UK and Europe.&lt;/p&gt;
&lt;p&gt;Things didn&amp;rsquo;t work out exactly as we&amp;rsquo;d planned, of course: I worked in the Redgate office for exactly two weeks before the UK went into the first lockdown. I&amp;rsquo;ve been working from home ever since &amp;ndash; at first from a small rental house (which we&amp;rsquo;d thought we wouldn&amp;rsquo;t spend all that much time in awake, haha) and now from a more comfortable home which we were very lucky to find and move to after the first lockdown let up.&lt;/p&gt;
&lt;h2 id="looking-back-i-was-lonely-as-hell-for-the-first-few-months"&gt;Looking Back, I Was Lonely as Hell for the First Few Months&lt;/h2&gt;
&lt;p&gt;I was very happy to have my job and my husband and dogs with me, but I felt very homesick, stressed, and incredibly lonely throughout spring and summer.&lt;/p&gt;
&lt;p&gt;But almost &lt;em&gt;everyone&lt;/em&gt; was lonely. When I talked to friends at home and mentioned I was homesick, some mentioned that they also felt homesick&amp;ndash; and they hadn&amp;rsquo;t gone anywhere. Everywhere, we were out of place, and worried about safety and health.&lt;/p&gt;
&lt;p&gt;To soothe my stress and worry, I relied on habits that don&amp;rsquo;t scale well: eating sweets, making cocktails, not moving much, and not setting many goals for myself. I was grateful to have a job and that my family was OK, even if they were far away. But I didn&amp;rsquo;t want to work on myself.&lt;/p&gt;
&lt;h2 id="6-months-into-the-covid-19-pandemic-ive-made-some-changes"&gt;6+ Months Into the COVID-19 Pandemic, I&amp;rsquo;ve Made Some Changes&lt;/h2&gt;
&lt;p&gt;Over time, I began feeling more and more sluggish, down, and anxious. I realized that I could work on good habits and help myself feel better, even while the pandemic continued.&lt;/p&gt;
&lt;p&gt;In early September I began working on eating better. &amp;ldquo;Eating better&amp;rdquo; looks radically different for different folks &amp;ndash; for &lt;em&gt;me&lt;/em&gt;, from experience the key to eating better is to largely eliminate processed sugar from my diet. If I avoid processed sugar most of the time, I begin enjoying vegetables more and generally make better decisions about what to eat, when to eat, and how much to eat.&lt;/p&gt;
&lt;p&gt;I also largely stopped drinking alcohol.&lt;/p&gt;
&lt;p&gt;I know. This post is a drag. WHAT IS A PANDEMIC WITHOUT ALCOHOL?&lt;/p&gt;
&lt;p&gt;Well, for me, it&amp;rsquo;s a pandemic where I make better daily decisions about my health. I haven&amp;rsquo;t stopped drinking entirely &amp;ndash; I think it&amp;rsquo;s OK for me to occasionally have a glass of wine when there&amp;rsquo;s cause for celebration. But &amp;ldquo;occasionally&amp;rdquo; is once every two weeks or less often. I try to avoid alcohol altogether if I&amp;rsquo;m feeling stressed or sad.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/my-workout-coach-freyja.jpeg"
alt="Photo with cycling coach Freyja" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;With my cycling coach, Freyja.&lt;/p&gt;
&lt;p&gt;Two weeks ago, I got an indoor cycle for the house and have started up daily spin workouts. I&amp;rsquo;m also challenging myself to do a bit of beginner yoga and to hold a plank pose once a day for however long I can manage.&lt;/p&gt;
&lt;h2 id="whats-made-the-biggest-difference"&gt;What&amp;rsquo;s Made the Biggest Difference?&lt;/h2&gt;
&lt;p&gt;Taking on the habit of exercise as a positive coping mechanism has been a massive help. I&amp;rsquo;m finding that physical exertion is helping me to be less anxious even in stressful times. I also quite like that I can set goals around my fitness, track them, and work to improve.&lt;/p&gt;
&lt;p&gt;And I also must say that my job with Redgate and my wonderful coworkers have made a huge difference. Not only is having the security of a regular paycheck a massive blessing, but working with understanding, open, and caring people is something I&amp;rsquo;m truly grateful for. My colleagues have helped me get through this weird, strange time.&lt;/p&gt;
&lt;h2 id="do-i-have-any-tips"&gt;Do I Have Any Tips?&lt;/h2&gt;
&lt;p&gt;My main tip is that it&amp;rsquo;s never too late to start working on a good habit.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t work on building good habits during the first part of this pandemic. But I eventually came to a time when I was ready and able to begin doing that. I don&amp;rsquo;t win anything by feeling bad about the first part &amp;ndash; there&amp;rsquo;s no point in that. I may as well celebrate what I&amp;rsquo;ve been able to do, and work on motivating myself to keep going.&lt;/p&gt;
&lt;h2 id="could-i-have-done-this-with-less-privilege"&gt;Could I Have Done This With Less Privilege?&lt;/h2&gt;
&lt;p&gt;This is a hard one, y&amp;rsquo;all. Not everyone is lucky enough to have a job, much less one with supportive colleagues. Not everyone has a family who are healthy and able. Not everyone has the time to obtain and cook fresh foods for dinner. Not everyone can afford an indoor cycle. Not everyone has a safe place to take walks outside. Not everyone has their health.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s an incredibly tough time. And if all you can do is get by each day, I certainly don&amp;rsquo;t want to imply that you are doing it wrong. You&amp;rsquo;re not. We each find our own way through this life the best that we can.&lt;/p&gt;
&lt;p&gt;Also, I&amp;rsquo;ve &lt;a href="https://kendralittle.com/2017/11/08/dear-sql-dba-i-thought-i-was-an-introvert-turns-out-i-was-anxious-as/"&gt;shared a bit about anxiety before&lt;/a&gt;, and to be clear I don&amp;rsquo;t think that simply &amp;ldquo;good habits&amp;rdquo; are a cure-all for anxiety and depression in general. Right now these are what is helpful to me, but I&amp;rsquo;ve been hugely helped by medical professionals before when that was what I needed.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re suffering significantly from anxiety and depression, I encourage you to please reach out for help and be open to seeking help from a doctor. Please know that you do not need to suffer alone.&lt;/p&gt;</description></item><item><title>Down Tools Week 2020 (10 minute video/podcast episode)</title><link>https://kendralittle.com/2020/08/06/down-tools-week-2020-10-minute-video-podcast-episode/</link><pubDate>Thu, 06 Aug 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/08/06/down-tools-week-2020-10-minute-video-podcast-episode/</guid><description>&lt;p&gt;It&amp;rsquo;s Down Tools Week at &lt;a href="http://redgate.com/blog"&gt;Redgate&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="about-this-episode"&gt;About This Episode&lt;/h2&gt;
&lt;p&gt;In this episode, I share what &amp;ldquo;Down Tools Week&amp;rdquo; is, what I&amp;rsquo;m working on this week, and why I think it&amp;rsquo;s a terrific experience for fostering creativity, innovation, and teamwork. In closing I share some thoughts on variations of this kind of project which you might use in your own organization.&lt;/p&gt;
&lt;h2 id="subscribe"&gt;Subscribe&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: Prefer to listen on the go? Get this episode on &lt;a href="https://podcasts.apple.com/ca/podcast/dear-sql-dba/id1117507864?mt=2"&gt;iTunes&lt;/a&gt;, &lt;a href="https://dearsqldba.libsyn.com/site/down-tools-week-2020"&gt;play the audio file&lt;/a&gt;, or find Dear SQL DBA in your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/39Jk03cN90k?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Common Antipatterns in Database Development (28 minute video/podcast episode)</title><link>https://kendralittle.com/2020/07/30/things-that-shouldnt-be-normal-in-database-development-28-minute-video-podcast-episode/</link><pubDate>Thu, 30 Jul 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/07/30/things-that-shouldnt-be-normal-in-database-development-28-minute-video-podcast-episode/</guid><description>&lt;p&gt;Many people use entrenched processes for database development that have been in place so long that it&amp;rsquo;s hard to imagine doing it any other way. In this episode, I share three things that should NOT be normal for database development&amp;ndash; but which are incredibly common.&lt;/p&gt;
&lt;h2 id="the-episode"&gt;The Episode&lt;/h2&gt;
&lt;p&gt;This episode is inspired by the book, &amp;ldquo;The Unicorn Project&amp;rdquo;, by Gene Kim.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: Prefer to listen? Get this episode on &lt;a href="https://podcasts.apple.com/ca/podcast/dear-sql-dba/id1117507864?mt=2"&gt;iTunes&lt;/a&gt;, &lt;a href="https://dearsqldba.libsyn.com/site/3-things-that-shouldnt-be-normal-in-database-development"&gt;play the audio&lt;/a&gt;, or find Dear SQL DBA in your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/GDvt8iqCE1U?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Everything I Never Wanted to Know About Collation (14 minute video/podcast episode)</title><link>https://kendralittle.com/2020/07/16/everything-i-never-wanted-to-know-about-collation-14-minute-video-podcast-episode/</link><pubDate>Thu, 16 Jul 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/07/16/everything-i-never-wanted-to-know-about-collation-14-minute-video-podcast-episode/</guid><description>&lt;p&gt;I&amp;rsquo;m not an expert on collation in SQL Server, but there are a few important facts which I&amp;rsquo;ve had to learn the hard way. In this episode I share the basics, along with helpful resources to learn more.&lt;/p&gt;
&lt;h2 id="localization-correction"&gt;Localization Correction&lt;/h2&gt;
&lt;p&gt;The default collation on a SQL Server install will be &amp;ldquo;the oldest available version that&amp;rsquo;s associated with each specific locale.&amp;rdquo; So if your Windows installation has a different localization than mine &amp;ndash; I always use English (USA) &amp;ndash; then you&amp;rsquo;ll see a different default collation than the one I discuss in the episode. The main point is still the same: it won&amp;rsquo;t be the recommended collation for *new* development.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Questions About SQL Server Collations You Were Too Shy to Ask, by Robert Sheldon - &lt;a href="https://www.red-gate.com/simple-talk/sql/sql-development/questions-sql-server-collations-shy-ask"&gt;https://www.red-gate.com/simple-talk/sql/sql-development/questions-sql-server-collations-shy-ask&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Collation and Unicode Support - &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support"&gt;https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: Prefer to listen on the go? Get this episode on &lt;a href="https://podcasts.apple.com/ca/podcast/dear-sql-dba/id1117507864?mt=2"&gt;iTunes&lt;/a&gt;, &lt;a href="https://dearsqldba.libsyn.com/site/everything-i-never-wanted-to-know-about-collation"&gt;play the audio file&lt;/a&gt;, or find Dear SQL DBA in your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/hoWG5Pd8pcE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>How to Spell and Capitalize tempdb for SQL Server</title><link>https://kendralittle.com/2020/07/15/how-to-spell-and-capitalize-tempdb-for-sql-server/</link><pubDate>Wed, 15 Jul 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/07/15/how-to-spell-and-capitalize-tempdb-for-sql-server/</guid><description>&lt;p&gt;No matter what I write in this post, some of y&amp;rsquo;all are going to tell me I&amp;rsquo;m wrong. That&amp;rsquo;s inevitable, because I&amp;rsquo;m writing about tempdb: a database so complex and mysterious in SQL Server, that even the spelling and capitalization of the database name is a topic of great disagreement.&lt;/p&gt;
&lt;h2 id="note-nearly-everyone-has-been-inconsistent-about-this"&gt;Note: Nearly Everyone Has Been Inconsistent About This&lt;/h2&gt;
&lt;p&gt;You might think, &amp;ldquo;This is easy, just check Microsoft&amp;rsquo;s documentation to find the answer.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a great idea, except you&amp;rsquo;ll find multiple variations of &amp;ldquo;tempdb&amp;rdquo; on Microsoft.com:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This docs page uses &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/databases/tempdb-database"&gt;tempdb&lt;/a&gt; (capitalized as &amp;ldquo;TempDB&amp;rdquo; in the link text)&lt;/li&gt;
&lt;li&gt;This docs page uses &lt;a href="https://docs.microsoft.com/en-us/sql/analytics-platform-system/tempdb-database"&gt;tempdb&lt;/a&gt; (lowercase even when first word in the title)&lt;/li&gt;
&lt;li&gt;This support page uses &lt;a href="https://support.microsoft.com/en-gb/help/307487/how-to-shrink-the-tempdb-database-in-sql-server"&gt;tempdb&lt;/a&gt; (But &amp;ldquo;Tempdb&amp;rdquo; when title case is needed) &amp;ndash; most Microsoft support pages seem to follow this pattern&lt;/li&gt;
&lt;li&gt;Bob Dorr, one of my favorite Microsofties who writes on SQL Server, likes to use all caps in &lt;a href="https://bobsql.com/sql-server-bdc-hints-and-tips-tempdb-disk-usage/"&gt;his post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pam Lahoud, another of my favorite Microsoft experts on SQL Server, uses tempdb (lowercase) in &lt;a href="https://techcommunity.microsoft.com/t5/sql-server/tempdb-files-and-trace-flags-and-updates-oh-my/ba-p/385937"&gt;her post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the good news is, if you&amp;rsquo;re writing for casual usage, there are a &lt;em&gt;lot&lt;/em&gt; of different alternate spellings out there, and that&amp;rsquo;s OK. Most people do NOT use a space and make &amp;ldquo;Temp DB&amp;rdquo; two words, but you&amp;rsquo;ll see variations of that around the internet as well.&lt;/p&gt;
&lt;p&gt;However, it can be nice to have a sense of the &amp;ldquo;most accepted&amp;rdquo; current spelling and capitalization of a term. This is especially useful if you&amp;rsquo;re building a tool with a GUI and you want it to look as &amp;ldquo;standard&amp;rdquo; as possible, or if you&amp;rsquo;re writing for a company website.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my take on what&amp;rsquo;s won the contentious &amp;ldquo;tempdb&amp;rdquo; spelling and capitalization wars.&lt;/p&gt;
&lt;h2 id="my-recommendation-is-tempdb-all-lowercase-but-title-cased-as-tempdb-when-required"&gt;My Recommendation Is: tempdb, All Lowercase, but Title Cased as Tempdb When Required&lt;/h2&gt;
&lt;p&gt;A few years back, I believe I saw &lt;a href="https://twitter.com/paulrandal"&gt;Paul Randal&lt;/a&gt; point out on Twitter that tempdb is a real database, and the database is spelled tempdb. This simple argument has persuaded quite a few of us who write in the SQL Server world that there&amp;rsquo;s no use for any spaces in there, and that the &amp;ldquo;db&amp;rdquo; bit shouldn&amp;rsquo;t be capitalized. (Time has passed and I can&amp;rsquo;t find the tweet, so hopefully I&amp;rsquo;m attributing this correctly.)&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/tempdb.png"
alt="A screenshot of the tempdb database appearing in SQL Server Management Studio&amp;#39;s object explorer. tempdb is all lower case and one word."&gt;
&lt;/figure&gt;
&lt;p&gt;You will find some variation in capitalization of tempdb on the SQL Skills blog, but Paul tends &lt;a href="https://www.sqlskills.com/blogs/paul/comprehensive-tempdb-blog-post-series/"&gt;to use lowercase &amp;ldquo;tempdb&amp;rdquo;&lt;/a&gt; even at the beginning of a bullet point.&lt;/p&gt;
&lt;p&gt;My colleague &lt;a href="https://twitter.com/auntkathi"&gt;Kathi Kellenberger&lt;/a&gt; is the editor of Simple Talk. On posts she edits, she uses lower case tempdb, but there are exceptions as in when tempdb is the first word in &lt;a href="https://www.red-gate.com/simple-talk/sql/performance/tempdb-heres-a-problem-you-didnt-know-you-have/"&gt;an article title&lt;/a&gt;. (This is a good article to look at as a style guide, in my opinion.)&lt;/p&gt;
&lt;p&gt;I have also noticed that other frequent writers in the Microsoft Data Platform space have standardized on &amp;ldquo;tempdb&amp;rdquo; somewhat, so if you choose this you are in good company:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/SQL_Kiwi"&gt;Paul White&lt;/a&gt;, who has written more deep technical content on tempdb than anyone else I know, &lt;a href="https://www.sql.kiwi/2012/08/temporary-tables-in-stored-procedures.html"&gt;uses tempdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/erikdarlingdata"&gt;Erik Darling&lt;/a&gt; uses &amp;ldquo;&lt;a href="https://www.erikdarlingdata.com/2019/04/sql-server-2019-in-memory-tempdb/"&gt;tempdb&lt;/a&gt;&amp;rdquo; in this new post on SQL Server 2019&amp;rsquo;s in-memory features for tempdb&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/AMtwo"&gt;Andy Mallon&lt;/a&gt; uses &amp;ldquo;tempdb&amp;rdquo; as he reminds you to &lt;a href="https://am2.co/2020/04/stop-trying-to-shrink-tempdb/"&gt;stop shrinking your tempdb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;As mentioned above, &lt;a href="https://www.google.com/search?q=site%3Asupport.microsoft.com+tempdb&amp;amp;oq=site%3Asupport.microsoft.com+tempdb"&gt;recent Microsoft support pages have largely standardized on this style&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I try to be consistent using &amp;ldquo;tempdb&amp;rdquo; on this site, and I mostly succeed at this lately. I tend to be massively inconsistent about title casing &lt;em&gt;in general&lt;/em&gt;, but I do my best. (Truth: I didn&amp;rsquo;t even capitalize the title of this post like I usually do, I had to go back and edit it after publishing, haha.)&lt;/p&gt;
&lt;h2 id="thanks-to-piers-for-the-suggestion-on-this-post"&gt;Thanks to Piers for the Suggestion on This Post&lt;/h2&gt;
&lt;p&gt;My colleague &lt;a href="https://medium.com/ingeniouslysimple/meet-the-team-piers-williams-software-engineer-8217d829d4b4"&gt;Piers is on the SQL Monitor team at Redgate&lt;/a&gt;. The team was chatting about how tempdb is so complicated that it&amp;rsquo;s not even obvious how to spell or capitalize it, and he said, &amp;ldquo;you know, maybe someone should write a blog post.&amp;rdquo; 💡&lt;/p&gt;
&lt;p&gt;And there&amp;rsquo;s always room for one more post about tempdb, right?&lt;/p&gt;</description></item><item><title>The Manager Guide to Git Training for DBAs - Video and Podcast</title><link>https://kendralittle.com/2020/07/09/the-managers-guide-to-git-training-for-dbas-video-podcast/</link><pubDate>Thu, 09 Jul 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/07/09/the-managers-guide-to-git-training-for-dbas-video-podcast/</guid><description>&lt;p&gt;Learning Git can be daunting for DBAs. In this 20 minute episode, I discuss why learning a VCS is necessary for DBAs, then give three tips on scoping your project, choosing the right tools, and making sure the project is successful.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The cheat sheet I mention in the episode is at &lt;a href="https://kendralittle.com/2019/11/27/my-git-cli-cheat-sheet/"&gt;/2019/11/27/my-git-cli-cheat-sheet/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A written version of this content is over at &lt;a href="https://www.red-gate.com/blog/the-managers-guide-to-git-training-for-database-administrators"&gt;https://www.red-gate.com/blog/the-managers-guide-to-git-training-for-database-administrators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kendralittle.com/dearsqldba/"&gt;Here&amp;rsquo;s the full episode list of Dear SQL DBA&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Y7OcSNNztpI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Thoughts as Pride Month 2020 Comes to a Close</title><link>https://kendralittle.com/2020/06/30/thoughts-as-pride-month-2020-comes-to-a-close/</link><pubDate>Tue, 30 Jun 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/06/30/thoughts-as-pride-month-2020-comes-to-a-close/</guid><description>&lt;p&gt;I&amp;rsquo;ve begun working on developing a couple of small habits this month, thanks largely to &lt;a href="https://twitter.com/amtwo"&gt;Andy Mallon&lt;/a&gt;&amp;rsquo;s helpful advocacy.&lt;/p&gt;
&lt;h2 id="becoming-more-consistent-in-sharing-my-pronouns"&gt;Becoming More Consistent in Sharing My Pronouns&lt;/h2&gt;
&lt;p&gt;My pronouns are &amp;ldquo;she/her.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I only became aware of why it&amp;rsquo;s helpful to share your pronouns in the last year. Before that, I hadn&amp;rsquo;t given much thought to it. Andy gives a great explanation of why this is helpful if this is something you are comfortable sharing &amp;ndash; here is one quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For some folks, the obvious pronouns aren’t their preferred pronouns. You share your pronouns to help normalize it so that everyone feels more comfortable sharing pronouns.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/amtwo"&gt;Andy Mallon&lt;/a&gt; in &lt;a href="https://am2.co/2020/06/hi-im-andy-my-pronouns-are-he-him/"&gt;Hi, I&amp;rsquo;m Andy. My pronouns are he/him.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Kendra-Bio-Slide-1024x574.jpg"
alt="A biography slide showing pronouns along with contact info"&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;ve started to edit my various biographies online to include my preferred pronouns. I plan to request that conference organizers include an optional space for pronouns in their slide deck templates as well when I speak at events. This is also an easy thing to include in my Slack profiles and other interactive tools.&lt;/p&gt;
&lt;h2 id="championing-anti-harassment-policies-and-codes-of-conduct-instead-of-being-a-jerk-about-them"&gt;Championing Anti-Harassment Policies and Codes of Conduct Instead of Being a Jerk About Them&lt;/h2&gt;
&lt;p&gt;My inner teenager isn&amp;rsquo;t so fond of things like dress codes &amp;ndash; and for some years I thought of a code of conduct as being pretty similar to a dress code: unnecessary in the modern world. I was very wrong.&lt;/p&gt;
&lt;p&gt;I now recognize that &lt;em&gt;harassment and discrimination happens frequently&lt;/em&gt;, and that it can easily happen in any group. Harassment and discrimination often impact those who are marginalized in a group the most. However, even those who are well known in a group may have a hard time speaking up when they are victimized or when they see a peer being victimized. Anti-harassment policies help people understand that they can and should speak up, they explain who to approach about the situation, and they also give a framework for the event handlers to follow when working through the situation. I now see that this is very useful and needed.&lt;/p&gt;
&lt;p&gt;I also now recognize that &lt;em&gt;anti-harassment policies are important for expressing community values of inclusion&lt;/em&gt;. It&amp;rsquo;s a good thing to talk about what we find important as a group, and to express what works for a community, and what doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;This is even good business sense.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The smartest thing for people who are running conventions is to recognize that in both the short and long run, it’s going to be better for your convention if everybody knows they’re going to be treated with respect,” he said. “If you don’t do that, the younger people, the people who are vital to your field, are no longer going to feel like your convention or conference is a welcome place, and they will create spaces that are more welcome to them. You don’t want to be the ones who are left behind.”&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/scalzi"&gt;John Scalzi&lt;/a&gt; quoted in &lt;a href="https://www.pcma.org/heres-what-to-include-in-your-meetings-harassment-policy/"&gt;Why Your Meeting Needs a Harassment Policy&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My commitment now is to asking if an event has an anti-harassment policy before I commit to speaking at it, and to also check and make sure that the policy is inclusive of&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;everyone&lt;/strong&gt; regardless of gender, gender identity and expression, age, sexual orientation, mental or physical ability, physical appearance, body size, race, ethnicity, religion (or lack thereof), technology choices.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/amtwo"&gt;Andy Mallon&lt;/a&gt; in &lt;a href="https://am2.co/2020/06/whats-important-in-a-code-of-conduct/"&gt;What&amp;rsquo;s Important in a Code of Conduct?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If it isn&amp;rsquo;t possible for the event to commit to this inclusion, it may not be the best place for me to spend my time right then. If it is possible for the event to do this, then I should send them positive feedback and help them promote this as part of a healthy community.&lt;/p&gt;
&lt;p&gt;These are small things, but I can do them. The more of us who do them, the easier it gets.&lt;/p&gt;</description></item><item><title>New Free Course: The Dirty Secrets of NOLOCK</title><link>https://kendralittle.com/2020/06/29/new-free-course-the-dirty-secrets-of-nolock/</link><pubDate>Mon, 29 Jun 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/06/29/new-free-course-the-dirty-secrets-of-nolock/</guid><description>&lt;p&gt;I&amp;rsquo;m excited to begin moving over courses from SQL Workbooks and making the material available here. The first course up for grabs is &lt;a href="https://kendralittle.com/course/the-dirty-secrets-of-nolock/"&gt;The Dirty Secrets of NOLOCK&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Dirty-Secrets-of-NOLOCK-300x300-1.png"
alt="Course thumbnail for The Dirty Secrets of NOLOCK course" width="200"&gt;
&lt;/figure&gt;
&lt;h2 id="a-little-bit-about-the-course"&gt;A Little Bit About the Course&lt;/h2&gt;
&lt;p&gt;What happens when you use NOLOCK hints in your code, or set your isolation level to READ UNCOMMITTED in SQL Server? In 50 minutes of online videos, you will learn what NOLOCK means, why NOLOCK can return incorrect results (and other problems), what allocation order scans are (and how to get them), and other risks and options for reading uncommitted data.&lt;/p&gt;
&lt;p&gt;Course lessons include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is NOLOCK? (3 minutes)&lt;/li&gt;
&lt;li&gt;The dirtiest secret: NOLOCK returns garbage data (10 minutes)&lt;/li&gt;
&lt;li&gt;The fast alternative to NOLOCK: indexing (5 minutes)&lt;/li&gt;
&lt;li&gt;Why NOLOCK is a misnomer (7 minutes)&lt;/li&gt;
&lt;li&gt;Bad phenomena that can occur under NOLOCK (2 minutes)&lt;/li&gt;
&lt;li&gt;Uses for NOLOCK: admin queries and garbage data (5 minutes)&lt;/li&gt;
&lt;li&gt;Allocation order scans (13 minutes)&lt;/li&gt;
&lt;li&gt;A common error with NOLOCK (6 minutes)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-course-is-free-but-please-donate-if-you-find-it-helpful"&gt;The Course Is Free, but Please Donate If You Find It Helpful&lt;/h2&gt;
&lt;p&gt;If you find my free courses helpful, show your appreciation by donating to one of the following organizations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.blackgirlscode.com/donations.html"&gt;Black Girls Code&lt;/a&gt; – whose mission is to “introduce programming and technology to a new generation of coders, coders who will become builders of technological innovation and of their own futures.”&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.thetrevorproject.org/donate"&gt;The Trevor Project&lt;/a&gt; – whose mission is to “end suicide among gay, lesbian, bisexual, transgender, queer &amp;amp; questioning young people.”&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.naacpldf.org/"&gt;The NAACP Legal Defense Fund&lt;/a&gt; – whose mission is to “achieve racial justice, equality, and an inclusive society.”&lt;/li&gt;
&lt;li&gt;&lt;a href="https://victoryfund.org/donate"&gt;The LGBTQ Victory Fund&lt;/a&gt; – which “works to change the face and voice of America’s politics and achieve equality for LGBTQ Americans by increasing the number of LGBTQ officials.”&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>How to Rename the Master Branch to Main in Git in Azure DevOps</title><link>https://kendralittle.com/2020/06/26/how-to-rename-the-master-branch-to-main-in-git-in-azure-devops/</link><pubDate>Fri, 26 Jun 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/06/26/how-to-rename-the-master-branch-to-main-in-git-in-azure-devops/</guid><description>&lt;p&gt;I believe that language matters, and that &lt;a href="https://tools.ietf.org/id/draft-knodel-terminology-00.html#rfc.section.1.1.1"&gt;it is worth our effort to move away from language associated with slavery and racism whenever possible&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-process"&gt;The Process&lt;/h2&gt;
&lt;p&gt;Azure DevOps doesn&amp;rsquo;t technically allow you to rename branches, but you can work around the issue by creating a new branch from master, setting the new branch as the default branch, and deleting the master branch. &lt;a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/require-branch-folders#rename-old-branches"&gt;Here&amp;rsquo;s the Microsoft documentation on this topic.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this video, I create a new default branch named main, then update a pipeline dependent on the default branch name.&lt;/p&gt;
&lt;h2 id="note-for-other-platforms"&gt;Note for Other Platforms&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: If you're using Git in something else like GitHub, you can &lt;a href="https://www.hanselman.com/blog/EasilyRenameYourGitDefaultBranchFromMasterToMain.aspx"&gt;do this in a simpler way&lt;/a&gt;.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/RAOR_yJrwX4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Create a Build with YAML for SQL Change Automation in Azure DevOps</title><link>https://kendralittle.com/2020/06/25/create-a-build-with-yaml-for-sql-change-automation-in-azure-devops/</link><pubDate>Thu, 25 Jun 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/06/25/create-a-build-with-yaml-for-sql-change-automation-in-azure-devops/</guid><description>&lt;p&gt;I used to make fun of YAML because I was scared of it. I still make fun of YAML, but I&amp;rsquo;m not scared of it anymore now that &lt;a href="https://twitter.com/sqldbawithbeard"&gt;Rob Sewell&lt;/a&gt; showed me how to avoid having to write it myself.&lt;/p&gt;
&lt;h2 id="video-tutorial"&gt;Video Tutorial&lt;/h2&gt;
&lt;p&gt;In this 11 minute video, I show how to set up a YAML build pipeline in Azure DevOps. My build is configured using a Local Agent, and will be building a database using Redgate&amp;rsquo;s SQL Change Automation.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/4rQ7M927f6U?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Use Chocolatey to Install Multiple SQL Server 2019 Instances for Testing</title><link>https://kendralittle.com/2020/06/05/use-chocolatey-to-install-multiple-sql-server-2019-instances-for-testing/</link><pubDate>Fri, 05 Jun 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/06/05/use-chocolatey-to-install-multiple-sql-server-2019-instances-for-testing/</guid><description>&lt;p&gt;I&amp;rsquo;m working on a project where it&amp;rsquo;s useful to automate environment setup and teardown for testing some devops deployment scenarios for databases using transactional replication.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-05-06-2020_13-22-54.jpg"
alt="Screenshot showing Chocolatey installation process" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="tools-im-using"&gt;Tools I&amp;rsquo;m Using&lt;/h2&gt;
&lt;p&gt;To make this easier, I&amp;rsquo;m using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://octopus.com/runbooks"&gt;Octopus Deploy Runbooks&lt;/a&gt; to organize a series of commands (they have a free tier, FYI)&lt;/li&gt;
&lt;li&gt;Chocolatey to install multiple &lt;a href="https://chocolatey.org/packages/sql-server-2019"&gt;SQL Server 2019 Developer Edition instances&lt;/a&gt; (I&amp;rsquo;ve &lt;a href="https://kendralittle.com/2019/12/02/installing-redgate-sql-toolbelt-with-chocolatey/"&gt;written about choco before&lt;/a&gt;, it&amp;rsquo;s also free)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-challenge"&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;While I&amp;rsquo;m not at all a fan of &amp;ldquo;stacking&amp;rdquo; multiple SQL Server Instances into one Windows Installation in production, it&amp;rsquo;s fine for this testing scenario.&lt;/p&gt;
&lt;p&gt;But I came across a little puzzle when trying to get this to work: when I tried to use choco install or choco upgrade for my second instance, it saw that SQL Server 2019 Developer Edition was already installed and did nothing. There is a &amp;ndash;force option which can be used to install additional instances, but the SQL Server Installer will throw an error if you use &amp;ndash;force and pass it information for an instance which is already installed. I needed to add a little extra PowerShell to make my script re-runnable and simple move on gracefully if an instance is already installed.&lt;/p&gt;
&lt;h2 id="the-solution"&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Here is the code pattern I finally landed on for each instance installation in my runbook:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$inst&lt;/span&gt;&lt;span class="p"&gt;=(&lt;/span&gt;&lt;span class="nb"&gt;get-itemproperty&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="py"&gt;InstalledInstances&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SQL1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SQL1 installed, no action taken&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;choco&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="nb"&gt;sql-server&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2019&lt;/span&gt; &lt;span class="n"&gt;-Y&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;-force&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;-params&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#39;/SQLSYSADMINACCOUNTS:domainname\username /SECURITYMODE:SQL /SAPWD:MyNotVerySecurePassword /IgnorePendingReboot /INSTANCENAME:SQL1 /INSTANCEDIR:c:\MSSQL\SQL1&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thanks to &lt;a href="https://stackoverflow.com/questions/7516337/powershell-list-all-sql-instances-on-my-system"&gt;this StackOverflow answer&lt;/a&gt; for helping me along.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m looking forward to sharing more of my progress on this project as I go!&lt;/p&gt;</description></item><item><title>Learn T-SQL for Free Online: Starting Today</title><link>https://kendralittle.com/2020/05/11/learn-tsql-for-free-online-starting-today/</link><pubDate>Mon, 11 May 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/05/11/learn-tsql-for-free-online-starting-today/</guid><description>&lt;figure&gt;&lt;img src="https://kendralittle.com/images/image-2-1024x576.png"
alt="T-SQL for Beginners course thumbnail"&gt;
&lt;/figure&gt;
&lt;p&gt;Thanks to the support of Redgate, I&amp;rsquo;ve launched a new course which teaches you the basics of T-SQL. The course is totally free, no logins required: we don&amp;rsquo;t even ask for the email address.&lt;/p&gt;
&lt;h2 id="check-out-the-course-on-redgate-university"&gt;Check Out the Course on Redgate University&lt;/h2&gt;
&lt;p&gt;The course is here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.red-gate.com/hub/university/courses/t-sql/tsql-for-beginners"&gt;https://www.red-gate.com/hub/university/courses/t-sql/tsql-for-beginners&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each week has an embedded video for the course, along with a link to the syllabus and scripts. The videos also have a timeline in case you wish to jump to a particular part of the discussion.&lt;/p&gt;
&lt;h2 id="want-to-join-live"&gt;Want to Join Live?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m publishing a new module each week, and we have five weeks to go. There&amp;rsquo;s a calendar reminder in the course if you want to join me live on Wednesdays at 3 pm BST / 11 AM EST, or you can catch the videos each week and follow along.&lt;/p&gt;
&lt;h2 id="want-to-learn-query-tuning-reporting-services-or-power-bi"&gt;Want to Learn Query Tuning, Reporting Services, or Power BI?&lt;/h2&gt;
&lt;p&gt;Redgate&amp;rsquo;s Community Circle initiative has other free courses on these topics. &lt;a href="https://www.red-gate.com/hub/university/courses/data-platform"&gt;Check out the free course list here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Learner's Guide to SQL Server Query Tuning</title><link>https://kendralittle.com/2020/05/01/learners-guide-to-sql-server-query-tuning/</link><pubDate>Fri, 01 May 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/05/01/learners-guide-to-sql-server-query-tuning/</guid><description>&lt;p&gt;Following on from my &lt;a href="https://kendralittle.com/2020/03/19/the-learners-guide-to-sql-server-performance-triage/"&gt;Learner&amp;rsquo;s Guide to SQL Server Performance Triage&lt;/a&gt;, I&amp;rsquo;m tackling Query Tuning. In this guide, I&amp;rsquo;m experimenting with an outline style rather than expanding each paragraph.&lt;/p&gt;
&lt;h2 id="why-do-we-need-query-tuning"&gt;Why Do We Need Query Tuning?&lt;/h2&gt;
&lt;p&gt;We’ve seen incredible improvements over the last 15 years:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Storage speed has massively increased due to advances in both storage technology and network bandwidth, CPUs have become much faster, and prices for memory have dropped dramatically.&lt;/li&gt;
&lt;li&gt;Database optimizers are constantly improving and finding ways to make queries more adaptable and to conquer areas of poor optimization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yet there are still professionals who make a good living tuning queries, and training others to tune queries. This process involves finding &lt;em&gt;specific slow queries&lt;/em&gt; that are key to the performance of an application and making strategic changes, whether in the code, the database structures, the instance configuration, or something else, to ensure that these specific queries consistently execute with a given speed or to a required standard of performance.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data sizes are also dramatically increasing&lt;/li&gt;
&lt;li&gt;Customer expectations about performance / speed of applications have also risen&lt;/li&gt;
&lt;li&gt;Customers expect to not have to wait for results now – they want to see current status right away&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="who-needs-to-do-query-tuning-who-doesnt"&gt;Who Needs to Do Query Tuning? Who Doesn&amp;rsquo;t?&lt;/h2&gt;
&lt;p&gt;Query tuning is done by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database administrators&lt;/li&gt;
&lt;li&gt;Developers who specialize in performance or in databases specifically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full stack developers don’t generally do query tuning unless they have a specific interest or work experience. This is a specialization rather than a “quick learning” task, so most full-stack developers simply don’t have time, and they need to engage a more specialized person to help. Teams who don’t have a readily available specialist may periodically bring in consultants to help with this.&lt;/p&gt;
&lt;p&gt;There are also many database administrators who manage databases where only &amp;ldquo;basic&amp;rdquo; availability and performance are required. These databases are used by cost-conscious organizations who don&amp;rsquo;t need every database to be tuned like a race-car: most of their databases are used by internal users who are used to moderate performance.&lt;/p&gt;
&lt;h2 id="what-skills-are-involved-in-query-tuning"&gt;What Skills Are Involved in Query Tuning?&lt;/h2&gt;
&lt;p&gt;I am not a wizard at TSQL, but I still became pretty good at query tuning. A very unscientific estimate of what skills make someone good at query tuning:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;65% - the time, interest, and resources (including a network of people to ask) to build an extensive map of “performance trivia” – this is patterns that don’t optimize well, edge conditions where performance goes bad, understanding of trace flags and configuration on TSQL.&lt;/li&gt;
&lt;li&gt;20% - interest and ability to learn how the database engine optimizes and processes queries using indexes and other resources, and what impacts concurrency as multiple queries run against a live database at the same time&lt;/li&gt;
&lt;li&gt;15% - understanding of the TSQL language and different ways of rewriting a query to produce a given result set&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="popular-built-in-query-tuning-tools-and-how-they-work-together"&gt;Popular Built-In Query Tuning Tools and How They Work Together&lt;/h2&gt;
&lt;h3 id="execution-plans"&gt;Execution plans&lt;/h3&gt;
&lt;p&gt;These are a “map” of how the query is run behind the scenes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Estimated” execution plans show the choices the optimizer has made to run the query, including how many rows it estimates will flow through different parts of the plan&lt;/li&gt;
&lt;li&gt;“Actual” execution plans are estimated plans updated with runtime statistics for things like how many rows flowed through the plan. If the plan is “adaptive” it will contain some information about which options were chosen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="wait-statistics"&gt;Wait Statistics&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Was the query slow because it took a long time to read a lot of data? Or because it couldn’t get a lock resource? Wait statistics help sort this out.&lt;/li&gt;
&lt;li&gt;Some wait statistics are included in actual execution plans as of SQL Server 2016 SP1+, but not all waits are tracked per query due to overhead&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="query-store"&gt;Query Store&lt;/h3&gt;
&lt;p&gt;SQL Server 2016+, all editions&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This feature tracks execution plans and aggregate runtime metrics (duration, cpu usage) along with aggregate wait stats&lt;/li&gt;
&lt;li&gt;This also has the ability to “freeze” plans&lt;/li&gt;
&lt;li&gt;Query Store information restores with the database itself, so it can be shared between environments if desired.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dynamic-management-views-and-performance-counters"&gt;Dynamic Management Views and Performance Counters&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;These help understand overall instance bottlenecks during the slow performance&lt;/li&gt;
&lt;li&gt;Example: overall wait statistics for the instance and metrics about storage latency during the time the queries performed poorly can help explain if the query really needs to be tuned
&lt;ul&gt;
&lt;li&gt;Query tuning frequently needs to do callbacks to “workload tuning”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="sql-trace-and-extended-events-traces"&gt;SQL Trace and Extended Events Traces&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;These are tricky to use for query tuning because it’s easy to slow down your workload and cause performance problems when tracing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Execution plans (filtering doesn’t help in this case, the plans are all examined / collected and the filter is applied too late)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait statistics (filtering can help here, but the data collected is so massive that you have to be very careful – and sorting through and querying the collected data is also quite cumbersome&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tough-problems"&gt;Tough Problems&lt;/h2&gt;
&lt;h3 id="parameter-sniffing"&gt;Parameter Sniffing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If a query is “sometimes fast, sometimes slow”, this &lt;em&gt;may&lt;/em&gt; be the cause&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For parameterized queries, SQL Server “sniffs” the values supplied for the parameters on first execution. This plan  is reused when other values are provided on subsequent execution unless something happens to cause recompilation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An example…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The CustomerOrderDetails procedure is initially compiled for &lt;code&gt;@CompanyId= 1001&lt;/code&gt;, a tiny customer with one order. A plan expecting a very small amount of orders is generated, which allocates very little memory for sorts and joins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The CustomerOrders procedure is then run for &lt;code&gt;@CompanyId= 128&lt;/code&gt;, our biggest customer with a million rows of details about their orders. As the query runs all the estimates are too small, there are inefficient one-by-one reads and memory spills are happening all over the place&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Someone restarts the SQL Server because “it’s slow”. This causes queries to all compile freshly. CustomerOrderDetails runs for the first time with &lt;code&gt;@CompanyId = 128&lt;/code&gt; and compiles a plan suited to many rows, and runs fast. Nobody understands what happened.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In this case the “slow plan” would not longer be in the DMVs. It would be stored in Query Store if that was in use.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="contention"&gt;Contention&lt;/h3&gt;
&lt;p&gt;It’s difficult to predict how queries will interact with one another in a live workload&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Shared resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Query workspace memory – a certain amount of memory needs to be allocated for sorts/ joins/ moving data around in a query. Lots of queries executing at once which need significant workspace memory can cause a problem with this.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sometimes the queries are estimating they need far more of this memory than they need and it will need to be tuned – people are unlikely to realize this outside of a live workload&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The number of queries doing modification and the approach to locking is difficult to predict outside of a live workload&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changes in query plans can cause blocking when it wasn’t present before&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Changes in server resources – even improvements – can cause blocking when it wasn’t present before&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: moving to a new server with more memory and faster CPUs saw an increase in lock waits, because storage waits went down and query execution sped up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="is-testing-in-production-required"&gt;Is Testing in Production Required?&lt;/h2&gt;
&lt;p&gt;Often, yes. One of the examples of this is parallelism.&lt;/p&gt;
&lt;p&gt;Tuning the level of parallelism for a workload, and for specific queries in that workload tends to be quite hardware specific, and you need a live environment.&lt;/p&gt;
&lt;p&gt;Workload “replays” are available within SQL Server’s toolkit but they are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time consuming to set up&lt;/li&gt;
&lt;li&gt;Only replays – you can’t “amp up” the activity meaningfully (deleting the same rows 10 times isn’t the same as deleting different rows 10 times)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="automated-query-tuning-history-and-evolution"&gt;Automated Query Tuning: History and Evolution&lt;/h2&gt;
&lt;h3 id="automated-plan-correction"&gt;Automated Plan Correction&lt;/h3&gt;
&lt;p&gt;SQL Server 2017, Enterprise Edition&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Built on top of Query Store&lt;/li&gt;
&lt;li&gt;Detects queries that are sometimes fast and sometimes slow&lt;/li&gt;
&lt;li&gt;Can recommend changes only if desired&lt;/li&gt;
&lt;li&gt;Can freeze plans, test if it helps, and react accordingly
&lt;ul&gt;
&lt;li&gt;Freezing is intended as a temporary fix – it’s recommended that a user evaluate the query for tuning as a longer term fix&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Very good feature for helping identify parameter sniffing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="intelligent-query-processing"&gt;Intelligent Query Processing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IQP features have been releasing over the last few versions of SQL Server&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Several of these features address common query tuning issues in SQL Server&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Scalar function inlining: Scalar functions have historically been very poorly optimized in SQL Server, causing slow row-by-row performance&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This feature “inlines” the functions into the larger execution plans and rewrites the plan accordingly&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adaptive joins: Adaptive logic is built into plans in some cases so that not only a “single path” for execution is available in the plan&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This currently applies to limited scenarios&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Batch mode execution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Optimizes how SQL Server handles scans of data by processing multiple values at once&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This originally was available only for queries which reference columnstore indexes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Batch mode for rowstore indexes introduced in SQL Server 2019&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="common-mistakes-and-pitfalls-in-query-tuning"&gt;Common Mistakes and Pitfalls in Query Tuning&lt;/h2&gt;
&lt;p&gt;Lack of connection between DBAs and Development teams&lt;/p&gt;
&lt;p&gt;Over-reliance on traces&lt;/p&gt;
&lt;p&gt;Lack of knowledge of execution plans in the team&lt;/p&gt;
&lt;p&gt;Overuse of hints&lt;/p&gt;
&lt;p&gt;Lack of understanding of SQL Server isolation levels and “optimistic” options&lt;/p&gt;</description></item><item><title>Join the Best Worst Code Contest Today at 5pm BST / Noon Eastern #BestWorstCode</title><link>https://kendralittle.com/2020/04/24/join-the-best-worst-code-contest-today-at-5pm-bst-noon-eastern-bestworstcode/</link><pubDate>Fri, 24 Apr 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/04/24/join-the-best-worst-code-contest-today-at-5pm-bst-noon-eastern-bestworstcode/</guid><description>&lt;p&gt;I have an idea! Let&amp;rsquo;s have a &amp;ldquo;Worst Code Contest.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="why-do-this"&gt;Why Do This?&lt;/h2&gt;
&lt;p&gt;Bad code is really fun: at least, when you write it on purpose. And other people&amp;rsquo;s bad code is &lt;em&gt;even more fun.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But seriously, I&amp;rsquo;ve needed to write a lot of bad code over the years when creating demos and reproducing various scenarios. It uses your brain in an unusual way, so it&amp;rsquo;s a fun thing, but it also teaches you a lot!&lt;/p&gt;
&lt;h2 id="how-to-play"&gt;How to Play&lt;/h2&gt;
&lt;p&gt;The game starts at 5pm BST / Noon Eastern / 9 AM Pacific today. &lt;a href="https://youtu.be/Xo76cGfhTD8"&gt;I&amp;rsquo;ll be livestreaming the contest here&lt;/a&gt;, but you can play whether or not you join the stream. Here&amp;rsquo;s how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I will post a challenge on Twitter to write your best worst code that either does a specific thing in TSQL or produces a specific result set when run against a SQL Server
&lt;ul&gt;
&lt;li&gt;I will use the tag &lt;a href="https://twitter.com/hashtag/BestWorstCode"&gt;&lt;/a&gt;&lt;a href="#BestWorstCode"&gt;&lt;/a&gt;&lt;a href="https://twitter.com/hashtag/BestWorstCode"&gt;#BestWorstCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I will push a &amp;ldquo;challenge file&amp;rdquo; describing the challenge to &lt;a href="https://github.com/LitKnd/BestWorstCode/tree/master"&gt;https://github.com/LitKnd/BestWorstCode/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There will be a 10 minute time limit for each challenge.
&lt;ul&gt;
&lt;li&gt;You can use whatever resources you want to put your solution together, but you must submit your solution within 10 minutes to compete. The solution needs to be in a set of short scripts (it can&amp;rsquo;t require cloning a whole repo or restoring a database &amp;ndash; the most beautiful awful code is succinct)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tweet back a link to your BEST WORST sample code using the tag &lt;a href="https://twitter.com/hashtag/BestWorstCode"&gt;#BestWorstCode.&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;You can save your code anywhere that works, as long as a link works and I can copy it to a clipboard and test it. One easy way to do this is to create a free GitHub account and &lt;a href="https://gist.github.com/discover"&gt;create a Gist for each sample&lt;/a&gt;. But blog posts are fine too, or whatever you like using that is easy to link to.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;ll do TWO challenges, so the contest will probably take 45 minutes altogether, with time for chatting through different submissions.&lt;/p&gt;
&lt;p&gt;You can join for one or both of the challenges. If this is fun, we can do it again sometime soon, too!&lt;/p&gt;
&lt;h2 id="what-do-i-need-to-have-installed-to-compete"&gt;What Do I Need to Have Installed to Compete?&lt;/h2&gt;
&lt;p&gt;You need three free things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A SQL Server (don&amp;rsquo;t use a production instance, LOL, &lt;a href="https://www.microsoft.com/en-gb/sql-server/sql-server-downloads"&gt;Developer Edition is free&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A copy of the pubs sample database (&lt;a href="https://github.com/microsoft/sql-server-samples/blob/master/samples/databases/northwind-pubs/instpubs.sql"&gt;script to create it is here&lt;/a&gt;, this is a Microsoft script &lt;a href="https://github.com/microsoft/sql-server-samples/blob/master/license.txt"&gt;shared under the MIT License&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A dream&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And truthfully, the dream is optional.&lt;/p&gt;
&lt;h2 id="do-i-have-to-play-to-join-the-livestream"&gt;Do I Have to Play to Join the Livestream?&lt;/h2&gt;
&lt;p&gt;Nope. &lt;a href="https://youtu.be/Xo76cGfhTD8"&gt;Join the livestream&lt;/a&gt; if you wanna chat while you play along, or just chat. You can also play without joining the livestream. It&amp;rsquo;s all good.&lt;/p&gt;
&lt;h2 id="is-there-a-prize"&gt;Is There a Prize?&lt;/h2&gt;
&lt;p&gt;You will win the admiration of two corgis and a sense of superiority that will last you all weekend long.&lt;/p&gt;
&lt;h2 id="lets-write-some-awful-code-together"&gt;Let&amp;rsquo;s Write Some Awful Code Together!&lt;/h2&gt;
&lt;p&gt;We can make something terrible &lt;em&gt;and&lt;/em&gt; beautiful at the same time.&lt;/p&gt;
&lt;h2 id="update-the-recording"&gt;Update: The Recording&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Xo76cGfhTD8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Make Database Code Reusable in SQL Source Control with Deployment Filters</title><link>https://kendralittle.com/2020/04/08/make-database-code-reusable-in-sql-source-control-with-deployment-filters/</link><pubDate>Wed, 08 Apr 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/04/08/make-database-code-reusable-in-sql-source-control-with-deployment-filters/</guid><description>&lt;p&gt;When I first began working with databases, I was lucky to land a job at a little start-up which had solid development and operations processes: all our code, including database code, was in version control. We had a strong database architect who instilled good coding practices into the way we managed database code as well: code was expected to be reusable whenever possible.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-08-04-2020_11-03-21.jpg"
alt="Photo of a circular light with a hole in the middle" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;For example, there was one set of code which managed error handling and logging for all our databases. It lived in one repository in version control, and was deployed into many databases. This code resided in its own schema, in this case the &amp;ldquo;EVT&amp;rdquo; schema. Similarly, there were other bits of &amp;ldquo;reusable&amp;rdquo; database code for managing configuration, transferring data between instances, documenting objects and procedures, and other common tasks.&lt;/p&gt;
&lt;h2 id="there-are-huge-benefits-to-establishing-reusable-pieces-of-code-for-your-databases"&gt;There Are Huge Benefits to Establishing Reusable Pieces of Code for Your Databases&lt;/h2&gt;
&lt;p&gt;The top five benefits I can think of, are&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It becomes easy to instill good practices, such as quality error handling, across different teams, without each team needing to learn in-depth about the topic. They simply need to learn how to call the reusable code.&lt;/li&gt;
&lt;li&gt;It is easy to test if core good practices have been implemented, by checking for the existence of the reusable code and whether it is working as part of deployment processes&lt;/li&gt;
&lt;li&gt;It is far more efficient to version and maintain code commonly used across databases by storing it in one repository and creating tests for that code itself&lt;/li&gt;
&lt;li&gt;Those doing production operations gain a consistent way to quickly gather information from databases in production across every environment. For example, 15 years later I still remember that I would run the EVT.LogList procedure to check for error output in databases when diagnosing an issue&lt;/li&gt;
&lt;li&gt;This vastly simplifies writing triage documentation for your databases&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="but-how-do-you-implement-this-with-modern-tooling"&gt;But How Do You Implement This with Modern Tooling?&lt;/h2&gt;
&lt;p&gt;Back in the day, our company wrote our own tooling to help us with this, because there simply weren&amp;rsquo;t any vendors who provided this functionality. Writing and maintaining that tooling required a significant investment on our part.&lt;/p&gt;
&lt;p&gt;These days, there are lots more tooling options available (and now I work for a vendor in this area, Redgate Software). However, it can be puzzling to determine how to implement reusable code in modern database tooling, especially &amp;ldquo;state-based&amp;rdquo; tooling such as Microsoft SSDT or Redgate SQL Source Control.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because when you do a state-based deployment, tooling of this type compares the object definitions which you have stored in source control with the target database, and generates commands to make the target database look exactly like the objects you have in source control.&lt;/p&gt;
&lt;p&gt;A diff occurring between a committed version of database code and a target database. In a state-based deployment, tooling automatically generates the code to be deployed from this differencing task. Without the use of filters or special tooling, any objects not in version control will be scripted to be dropped.&lt;/p&gt;
&lt;p&gt;This becomes tricky if you are only deploying &lt;em&gt;part&lt;/em&gt; of a database, especially if there are any dependencies which exist between the part of the database you are deploying and the rest of the database. If you do nothing, the state-based solution will assume that you want to make the target database look exactly like what is in version control and &lt;em&gt;only&lt;/em&gt; like what is in version control, so it will script DROP commands for anything else.&lt;/p&gt;
&lt;h2 id="deployment-filters-simplify-managing-reusable-database-code"&gt;Deployment Filters Simplify Managing Reusable Database Code&lt;/h2&gt;
&lt;p&gt;How you solve this problem depends on your tooling. Since I work for Redgate, I naturally invest my time in working with our tooling the most &amp;ndash; so from here on out I&amp;rsquo;ll be talking about deploying SQL Source Control projects with &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/"&gt;SQL Change Automation&lt;/a&gt;, which has features which help with this problem.&lt;/p&gt;
&lt;p&gt;SQL Change Automation has graphic extensions/plugins as well as PowerShell cmdlets. I&amp;rsquo;ll refer to the PowerShell cmdlets when describing how to do this, but know that the very same functionality is available in the plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If your reusable code is in a repository all by itself, you &lt;a href="https://documentation.red-gate.com/sca4/reference/powershell-cmdlets/new-databasereleaseartifact"&gt;can use the -IgnoreAdditional option&lt;/a&gt; to deploy everything from your build package and simply ignore (aka don&amp;rsquo;t drop) additional objects in the target database&lt;/li&gt;
&lt;li&gt;If your reusable code is in a shared repository (perhaps with other reusable code, perhaps with something else), and you want to build the whole thing but only deploy part of the code (say, a schema), this can be done by specifying a filter file saved from SQL Compare &lt;a href="http://-FilterPath"&gt;using -FilterPath when you create the release artifact&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, no matter how you are versioning the code you want to make reusable, there is a path towards being able to safely deploy this code in an automated fashion to target databases as needed.&lt;/p&gt;
&lt;h2 id="reusable-code-at-work"&gt;Reusable Code at Work&lt;/h2&gt;
&lt;p&gt;There are other interesting patterns which deployment filter files enable. For example, &lt;a href="https://twitter.com/PlantBasedSQL"&gt;Chris Unwin&lt;/a&gt; and I recently worked on a case where we were asked how to make schema based deployments to a large number of production databases as efficient as possible. This can be done with a variety of orchestrators &amp;ndash; in this example the use case is to have Octopus Deploy manage the release orchestration.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve just published a 46 minute YouTube video, &amp;ldquo;Reusable Schema Deployments with SQL Source Control and Octopus Deploy&amp;rdquo; which gives you a view of this at work. (To be clear, Chris 100% did all the hard work here and I&amp;rsquo;m riding his coattails!) If you&amp;rsquo;d like to check out individual parts of this video, a table of content with links is at the bottom of this post.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/j-X1ePOL1xY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=40s"&gt;00:40&lt;/a&gt; Overview of the problem we are solving: finding the most efficient way to deploy individual schemas (which are each stored in version control once) to a large number of production databases (which each may contain a mix of some or all of the schemas)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=180s"&gt;3:00&lt;/a&gt; A discussion of state and migrations approaches, and why we are discussing a state-based solution with SQL Source Control for this problem&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=310s"&gt;5:10&lt;/a&gt; An overview of the two parts of the solution: Release Artifacts are reusable, and deployment filters effectively &amp;ldquo;ignore&amp;rdquo; anything that is excluded by the filter (it will not script &amp;ldquo;drop&amp;rdquo; commands for them)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=485s"&gt;8:05&lt;/a&gt; An overview of the solution workflow&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=632s"&gt;10:32&lt;/a&gt; Demo begins! An overview of the databases used for the prototype environment proving this out&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=840s"&gt;14:00&lt;/a&gt; An overview of the build pipeline in Azure DevOps Services which builds SQL Source Control and hooks things up with Octopus Deploy &amp;ndash; and a brief excursion where Chris de-mystifies YAML and shows Kendra that dealing with it in Azure DevOps is MUCH easier than she thought&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=1320s"&gt;22:00&lt;/a&gt; A view of how the prototype environment works in Octopus Deploy (including a view of the lovely aquatic dark theme in Octopus now)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=1440s"&gt;24:00&lt;/a&gt; A view of the procedural deployment steps in Octopus Deploy using Redgate SQL Change Automation and an explanation of how steps can be configured to run against certain environments&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=1680s"&gt;28:00&lt;/a&gt; A view of the filters created for schema deployment, and a demo of how to create them in SQL Compare&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=1995s"&gt;33:15&lt;/a&gt; A view of how managing &amp;ldquo;environments&amp;rdquo; as groups of databases makes it easy to perform deployments of a schema to many databases with a minimum of steps in Octopus Deploy&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=2102s"&gt;35:02&lt;/a&gt; Time to show it at work! Chris kicks off a deployment&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=2185s"&gt;36:25&lt;/a&gt; A review of the Release Artifacts created, and the changes and code therein&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=j-X1ePOL1xY&amp;amp;t=2439s"&gt;40:39&lt;/a&gt; Summary /recap of the benefits of this approach&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Connecting to the SQL Server Community Online: Uplifting Folks</title><link>https://kendralittle.com/2020/03/23/connecting-to-the-sql-server-community-online-uplifting-folks/</link><pubDate>Mon, 23 Mar 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/03/23/connecting-to-the-sql-server-community-online-uplifting-folks/</guid><description>&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-23-03-2020_17-14-52.jpg"
alt="Neon sign of a speech bubble around the word &amp;#39;hello&amp;#39;" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;We&amp;rsquo;ve got a session coming up in the &lt;a href="https://www.red-gate.com/hub/events/redgate-events/redgate-streamed/"&gt;free Redgate Streamed virtual conference&lt;/a&gt; on, &amp;ldquo;How database DevOps levels up remote work.&amp;rdquo; When thinking about that session I began thinking about other ways to improve remote work.&lt;/p&gt;
&lt;p&gt;While I worked remotely for nearly ten years until recently and &lt;a href="https://www.sqlservercentral.com/editorials/kendras-top-3-tips-for-working-remotely"&gt;have established practices which work well for me&lt;/a&gt; , moving to another country and the general chaos and uncertainty right now as the world tries to cope with a global pandemic have increased my feelings of worry and loneliness.&lt;/p&gt;
&lt;p&gt;I have found that certain folks in my Twitter feed help me feel connected, combat my worry, and also add some good old fashioned nerdiness to my day. They level up my remote work day!&lt;/p&gt;
&lt;p&gt;If you could use a few more connections in your life and would like to get started on Twitter, I highly recommend following these friendly folks who love working with data, and who bring thoughtfulness and happiness into the community:&lt;/p&gt;
&lt;h2 id="cathrine-wilhelmsen-aka-cathrinew"&gt;&lt;a href="https://twitter.com/cathrinew"&gt;Cathrine Wilhelmsen, aka @cathrinew&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cathrine loves teaching and learning, and her tweets always teach me something, give me something to think about, or improve my day in some way.&lt;/p&gt;
&lt;p&gt;Cathrine&amp;rsquo;s bio: &amp;ldquo;SQL/Data geek, Microsoft Data Platform MVP, speaker, blogger and chronic volunteer. Taller on Twitter! Loves sci-fi, chocolate, coffee, and cats. She/Her.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="mala-mahadevan-aka-sqlmal"&gt;&lt;a href="https://twitter.com/sqlmal"&gt;Mala Mahadevan, aka @sqlmal&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mala constantly learns and shares. She is one of the kindest people I know as well as an honest person, and her tweets remind me that one can confront things and be kind at the same time.&lt;/p&gt;
&lt;p&gt;Mala&amp;rsquo;s bio: &amp;quot; SQL Server Enthusiast, PASS Regional Mentor-NE region, here to learn and follow all things SQL. My views do not reflect views of my employer. She/Her&amp;quot;&lt;/p&gt;
&lt;h2 id="drew-furgiuele-aka-pittfurg"&gt;&lt;a href="https://twitter.com/Pittfurg"&gt;Drew Furgiuele, aka @Pittfurg&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Drew loves dogs, databases, and people who are doing their best.&lt;/p&gt;
&lt;p&gt;Drew&amp;rsquo;s bio: &amp;ldquo;KE8SQL. Former Data Platform MVP turned Microsoft PFE. Co-host of &lt;a href="https://t.co/n6tSlfcAWz?amp=1"&gt;http://doingtheirbest.com&lt;/a&gt; podcast. Tweets and opinions my own. The toughest guy in Letterkenny&amp;rdquo;&lt;/p&gt;
&lt;h2 id="jess-pomfret-aka-jpomfret"&gt;&lt;a href="https://twitter.com/jpomfret"&gt;Jess Pomfret, aka @jpomfret&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Jess is stellar at automation. Her twitter feed also always makes me feel like doing something active, even if it&amp;rsquo;s just a quick set of exercises in my home office (and as a lazy person I &lt;em&gt;really need this kind of inspiration&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;Jess&amp;rsquo; bio: &amp;ldquo;She/Her. SQL Server, PowerShell, Crossfit, Proper Football&amp;rdquo;&lt;/p&gt;
&lt;h2 id="andy-mallon-aka-amtwo"&gt;&lt;a href="https://twitter.com/AMtwo"&gt;Andy Mallon, aka @AMtwo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Andy provides a lot of dog photos and asks essential questions in polls, like &amp;ldquo;What&amp;rsquo;s the appropriate thing to say when you toot?&amp;rdquo; These are the things that keep me sane. He&amp;rsquo;s really good at managing databases too and he probably even posts about that sometimes.&lt;/p&gt;
&lt;p&gt;Andy&amp;rsquo;s bio: &amp;quot; Boston Terror. Database Artist. Dog Dad. Carbatarian. I am a four letter word. Vaccinated. he/him. &lt;a href="https://twitter.com/search?q=%23Food&amp;amp;src=hashtag_click"&gt;#Food&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23Politics&amp;amp;src=hashtag_click"&gt;#Politics&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23SQL&amp;amp;src=hashtag_click"&gt;#SQL&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23Activism&amp;amp;src=hashtag_click"&gt;#Activism&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23TeamOxfordComma&amp;amp;src=hashtag_click"&gt;#TeamOxfordComma&lt;/a&gt;&amp;quot;&lt;/p&gt;
&lt;h2 id="steve-jones-aka-way0utwest"&gt;&lt;a href="https://twitter.com/way0utwest"&gt;Steve Jones, aka @way0utwest&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Steve lives on a ranch, so he&amp;rsquo;s got horse photos, ranch photos, and mountain views. He&amp;rsquo;s also got a really grounded-but-positive perspective on things. He&amp;rsquo;s thoughtful. He has good ideas. (Proof: he not only founded SQLServerCentral, he also co-founded SQLSaturday events back in the day!)&lt;/p&gt;
&lt;p&gt;Steve&amp;rsquo;s bio is truly minimalist. It is: &amp;ldquo;Editor, &lt;a href="https://t.co/Xt1ZI2nl5d?amp=1"&gt;http://SQLServerCentral.com&lt;/a&gt;&amp;rdquo;&lt;/p&gt;
&lt;h2 id="buck-woody-aka-buckwoodymsft"&gt;&lt;a href="https://twitter.com/BuckWoodyMSFT"&gt;Buck Woody, aka @BuckWoodyMSFT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Buck is more than a person. He&amp;rsquo;s more of an experience. Follow Buck for learning resources, tutorials on loads of things across the data platform and analytics, terrible puns that you&amp;rsquo;ll still laugh at, and also a lot of kindness.&lt;/p&gt;
&lt;p&gt;Buck&amp;rsquo;s bio is empty.&lt;/p&gt;
&lt;h2 id="there-are-loads-of-awesome-people-in-the-community-and-this-isnt-an-exhaustive-list-not-by-far"&gt;There Are Loads of Awesome People in the Community, and This Isn&amp;rsquo;t an Exhaustive List: Not by Far!&lt;/h2&gt;
&lt;p&gt;These are simply the people I thought of first today! If I didn&amp;rsquo;t list you, it doesn&amp;rsquo;t mean I don&amp;rsquo;t love ya :)&lt;/p&gt;</description></item><item><title>Outlining My Session: Index Tuning in an Agile World</title><link>https://kendralittle.com/2020/03/20/outlining-my-session-index-tuning-in-an-agile-world/</link><pubDate>Fri, 20 Mar 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/03/20/outlining-my-session-index-tuning-in-an-agile-world/</guid><description>&lt;p&gt;I&amp;rsquo;m giving a session on index tuning at the upcoming Redgate Streamed free online conference. The conference will be held &lt;a href="https://www.red-gate.com/hub/events/redgate-events/redgate-streamed/"&gt;April 1-3 2020, register here and join us!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I love talking about index tuning and I know this area well, so I&amp;rsquo;m excited to put together this new session. I thought it would be fun to share my process of outlining and creating the session, leading up to the event.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-20-03-2020_16-00-06.jpg"
alt="A small sprouting plant" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;The session title and abstract I wrote this week is&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Index Tuning in an Agile World&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Software developers increasingly work across databases and applications, and there are fewer and fewer dedicated database developers each year. This produces a new opportunity for database administrators and developers who are interested in performance: the role of the incremental index tuner. In this session you will learn a framework for developing and tuning indexes in SQL Server, and how to apply this framework in an Agile development context.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="who-is-my-audience-what-is-my-goal"&gt;Who Is My Audience? What Is My Goal?&lt;/h2&gt;
&lt;p&gt;Whenever I&amp;rsquo;m writing or rehearsing a session, I remind myself to think about who my ideal audience is. In this case it&amp;rsquo;s fairly broad: it&amp;rsquo;s developers or DBAs who care about performance of their code, but they aren&amp;rsquo;t yet experts at index tuning. The interesting thing right now is that often the people in this audience don&amp;rsquo;t have all of the information they need to do index tuning by themselves: from the DBA side, they typically have access to the production system but often don&amp;rsquo;t have access to the codebase, or the design of the queries. From the developer side, they often have the opposite situation: they can get to the code and change it if needed, but they don&amp;rsquo;t have regular access to production.&lt;/p&gt;
&lt;p&gt;My goal in this session is to get all of these people started by showing an example of index tuning, and proposing a workflow in which a performance problem can be identified, a change to indexes can be suggested and reviewed, and the change can be agreed upon and deployed through the environments needed to reach production.&lt;/p&gt;
&lt;h2 id="my-initial-outline"&gt;My Initial Outline&lt;/h2&gt;
&lt;p&gt;I like to begin putting together sessions with an outline of how I think the session will flow. This outline may change &lt;em&gt;entirely&lt;/em&gt; over the course of writing the session, but it feels right to start with it. Here&amp;rsquo;s what I&amp;rsquo;m thinking we can cover in an hour:&lt;/p&gt;
&lt;h3 id="intro-the-problem-space"&gt;Intro: The Problem Space&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Disconnected teams: developers lack production access, DBAs lack access to code and ability to change it&lt;/li&gt;
&lt;li&gt;Both groups often are unfamiliar with index tuning&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="learning-by-example-the-goal-workflow"&gt;Learning by Example: The Goal Workflow&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Show an example query with erratic performance&lt;/li&gt;
&lt;li&gt;Demo: How can the problem be discovered by a DBA with production access?&lt;/li&gt;
&lt;li&gt;Demo: How can the problem be discovered by a developer without production access?&lt;/li&gt;
&lt;li&gt;Example: testing different indexes to improve performance in a development environment&lt;/li&gt;
&lt;li&gt;Example: using work items and a pull request workflow to propose index changes&lt;/li&gt;
&lt;li&gt;Gotchas: where can this go wrong?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="how-to-improve-your-workflow"&gt;How to Improve Your Workflow&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;What if your database code isn&amp;rsquo;t in version control yet? How do you get started?&lt;/li&gt;
&lt;li&gt;What if other folks don&amp;rsquo;t want to change / want to keep things they way they are?&lt;/li&gt;
&lt;li&gt;What about designing indexes from the ground up instead of tuning an existing system?&lt;/li&gt;
&lt;li&gt;References / links for learning Git, branching / merging strategies&lt;/li&gt;
&lt;li&gt;References for index tuning basics and further learning&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ll be working on this session more next week, so stay tuned to see how it comes together.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m grateful that I get to work with others in the community in this topsy-turvy time, and that I have you as a reader. Stay safe, take good care of yourself and your families, and I hope that you are healthy and able to &lt;a href="https://www.red-gate.com/hub/events/redgate-events/redgate-streamed/"&gt;join us o n April 1-3 2020, for Redgate Streamed.&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Announcing Redgate Streamed, April 1-3 2020</title><link>https://kendralittle.com/2020/03/19/announcing-redgate-streamed-april-1-3-2020/</link><pubDate>Thu, 19 Mar 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/03/19/announcing-redgate-streamed-april-1-3-2020/</guid><description>&lt;p&gt;We&amp;rsquo;re thrilled to announce Redgate Streamed: a 3 day online virtual community conference, to be held April 1-3, 2020. Register at &lt;a href="https://www.red-gate.com/hub/events/redgate-events/redgate-streamed/"&gt;Redgate.com/RedgateStreamed&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="about-the-event"&gt;About the Event&lt;/h2&gt;
&lt;p&gt;In this 9 minute livestream, I give you a rundown of the event schedule and tells you why I&amp;rsquo;m excited about each session.&lt;/p&gt;
&lt;h2 id="support-covid-19-response"&gt;Support COVID-19 Response&lt;/h2&gt;
&lt;p&gt;For every registration that attends Redgate streamed, live or on-demand, we&amp;rsquo;ll donate $1 to the World Health Organization&amp;rsquo;s COVID-19 response fund (in addition to a separate donation we&amp;rsquo;ll be making. Even if you can&amp;rsquo;t join us live, &lt;a href="https://www.red-gate.com/hub/events/redgate-events/redgate-streamed/"&gt;be sure to register&lt;/a&gt; and you&amp;rsquo;ll receive the recordings to watch on-demand, plus you&amp;rsquo;ll help us raise our gift level!&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/W1O8o-3YAF4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>The Learner's Guide to SQL Server Performance Triage</title><link>https://kendralittle.com/2020/03/19/the-learners-guide-to-sql-server-performance-triage/</link><pubDate>Thu, 19 Mar 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/03/19/the-learners-guide-to-sql-server-performance-triage/</guid><description>&lt;p&gt;I&amp;rsquo;m introducing a series of &amp;ldquo;learner&amp;rsquo;s guides&amp;rdquo;: overviews of a given topic, chock full of links and references. For this first post, the information is based on what I learned when I was part of the team at Brent Ozar Unlimited who put together the &lt;a href="https://www.brentozar.com/first-aid/"&gt;original First Responder Kit&lt;/a&gt; and built a related consulting practice using those tools.&lt;/p&gt;
&lt;h2 id="what-is-performance-triage-and-when-do-we-do-it"&gt;What Is Performance Triage, and When Do We Do It?&lt;/h2&gt;
&lt;p&gt;Performance triage is done when a production database is suspected to be the cause of slowness or of loss of availability. Many times when perf triage is done it&amp;rsquo;s unclear what the source of the problem is, and the goal is to either identify what is happening in the database or instance to cause this problem, or to rule out the database as much as possible.&lt;/p&gt;
&lt;p&gt;In other words, most applications aren&amp;rsquo;t written with enough built in observability to clearly tell if the problem is in the application layer, the database layer, the network or somewhere else. But the database is often an early suspect in an investigation.&lt;/p&gt;
&lt;h2 id="who-does-performance-triage"&gt;Who Does Performance Triage?&lt;/h2&gt;
&lt;p&gt;Database administrators (DBAs) have been the main people to do performance triage over the last 20 years. This is largely due to separation of duties: DBAs have typically been responsible for the performance and availability of production databases, while access has been limited to these environments for developers. Often DBAs are part of an IT group which is managed as a separate business unit from that of software development. DBAs also often are responsible for databases developed externally from the company, such as vendor databases.&lt;/p&gt;
&lt;p&gt;In recent years, responsibility for production environments has been shifting, at least when it comes to in-house development. As organizations work to be able to deliver new features to customers more quickly in competitive environments, movements such as Agile development, DevOps, and Infrastructure as Code have been shifting roles: it is more common than ever for developers to need to maintain responsibility for their code throughout the entire deployment process, and for Database Administrators to be asked to participate in the development process earlier to help with quality design and testing.&lt;/p&gt;
&lt;p&gt;Monitoring tooling also better enables communication to both of these teams, and automation is used to help manage permissions for different environments, allowing access to be granted quickly, but only when it is needed and approve.&lt;/p&gt;
&lt;h2 id="dmvs-revolutionized-the-way-performance-triage-is-done"&gt;&amp;ldquo;DMVs&amp;rdquo; Revolutionized the Way Performance Triage Is Done&lt;/h2&gt;
&lt;p&gt;Prior to the release of SQL Server 2005, &amp;ldquo;Profiling&amp;rdquo; using &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/sql-trace/sql-trace"&gt;SQL Trace&lt;/a&gt; was the most widely used methodology, most often run by the SQL Server Profiler tool.&lt;/p&gt;
&lt;p&gt;SQL Server 2005 changed methodologies dramatically with the introduction of &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/system-dynamic-management-views"&gt;Dynamic Management Views and functions&lt;/a&gt;, which are commonly referred to as &amp;ldquo;DMVs&amp;rdquo;. DMVs hold a rich amount of information regarding the present and recent aggregate performance of a SQL Server instance and its databases. The major benefits of DMVs include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Much lighter overhead than tracing&lt;/li&gt;
&lt;li&gt;Data on everything from internal performance of the SQL Server to which user queries have been run and how often&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, many DMVs in SQL Server are cleared when different events occur, such as an instance restarting, a database going offline, a query recompiling, a configuration changing, or memory pressure. For this reason, monitoring tools are very popular and are used to harvest information from DMVs (as well as the sources listed below), store them in a separate repository, and use them to provide historic performance information.&lt;/p&gt;
&lt;h2 id="sources-for-information-in-performance-triage"&gt;Sources for Information in Performance Triage&lt;/h2&gt;
&lt;p&gt;In addition to dynamic management views, monitoring tools and folks performing manual triage often reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Operating system error logs&lt;/strong&gt;. Windows is most commonly used to run SQL Server in production environments, so this is usually the Windows Event log, both System and Application logs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Cluster Manager logs&lt;/strong&gt; if Failover Clusters and / or Availability Groups are in use&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL Server Error Log&lt;/strong&gt; - SQL Server maintains its own log of errors&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtualization metrics&lt;/strong&gt; (if applicable)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance counters&lt;/strong&gt; - SQL Server performance counters can be accessed via Perfmon or &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-performance-counters-transact-sql"&gt;queried via SQL Server in sys.dm_os_performance_counters&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;There is some overlap between performance counters and DMVs - occasionally perf counters are either easier to use or hold information not available or easily attainable from DMVs&lt;/li&gt;
&lt;li&gt;OS performance counters are available via Perfmon and are often relevant as well&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL Trace&lt;/strong&gt; (either &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/sql-trace/sql-trace"&gt;Server Side SQL Trace or live SQL Trace via SQL Profiler&lt;/a&gt;) and &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/extended-events/quick-start-extended-events-in-sql-server"&gt;Extended Events&lt;/a&gt; (XE) traces - these have more impact on the SQL Server and it&amp;rsquo;s easier to cause a performance problem with them, but they can be useful when handled with care&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query execution plans&lt;/strong&gt; and related &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-stats-transact-sql"&gt;query runtime metrics&lt;/a&gt; - &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/display-the-estimated-execution-plan"&gt;execution plans&lt;/a&gt; may be harvested via DMVs, &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store"&gt;Query Store&lt;/a&gt;, or a trace (warning: these are expensive to collect in traces, even using Extended Events)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-is-performance-triage-difficult"&gt;When Is Performance Triage Difficult?&lt;/h2&gt;
&lt;p&gt;Performance triage is most difficult when monitoring of the SQL Server either isn&amp;rsquo;t in place, or monitoring is only being done by a high level &amp;ldquo;platform&amp;rdquo; style monitoring system such as &lt;a href="https://docs.microsoft.com/en-us/system-center/scom/welcome"&gt;System Center Operations Manager (SCOM)&lt;/a&gt;. This is because a significant amount of critical information about performance is cleared when failovers happen, restarts occur, configuration is changed, or memory pressure occurs.&lt;/p&gt;
&lt;p&gt;While &amp;ldquo;platform&amp;rdquo; tools sometimes do have specialized management packs to attempt to gather some deeper information, in practice most teams find it difficult to harvest and use this information. For this reason, it&amp;rsquo;s quite common for teams to use both a platform level tool for high level monitoring across many types of databases, applications, and services, as well as a specialized SQL Server monitoring tool for monitoring databases and instances, both on-prem and in the cloud.&lt;/p&gt;
&lt;p&gt;While it is possible to do performance triage in a reactive model and begin gathering information after the problem happens, in this mode you are left waiting for the problem to happen again before you can begin to diagnose it.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to see an example of SQL Server specialized monitoring running against a live system, &lt;a href="https://monitor.red-gate.com/"&gt;Redgate&amp;rsquo;s SQL Monitor&lt;/a&gt; has an online demo which runs against environments including the live &lt;a href="https://www.sqlservercentral.com/"&gt;SQL Server Central databases&lt;/a&gt; as well as cloud PAAS workloads. (Disclaimer: I work for Redgate.)&lt;/p&gt;
&lt;h2 id="sql-server-performance-triage-checklist"&gt;SQL Server Performance Triage Checklist&lt;/h2&gt;
&lt;h3 id="a-frequent-check-whats-happening-now"&gt;A Frequent Check: What&amp;rsquo;s Happening Now?&lt;/h3&gt;
&lt;p&gt;Whenever I begin triage, I often start with checking: what queries are running RIGHT NOW? No matter what monitoring system or tooling is in place I like doing this check with the free utility &lt;a href="http://whoisactive.com/"&gt;sp_WhoIsActive&lt;/a&gt;. I like this because sp_WhoIsActive is a stored procedure you may run against the instance, and like many operations people I like to see information in multiple tools &amp;ndash; so a monitoring tool can help confirm what I see in sp_WhoIsActive and vice-versa.&lt;/p&gt;
&lt;p&gt;Throughout triage I typically stop and run sp_WhoIsActive multiple times to confirm that the instance is responding quickly and that I don&amp;rsquo;t see signs that something is going wrong. After all, you never want to make a problem worse by triaging it, and you don&amp;rsquo;t want to be oblivious to what is going on while looking at logs of past behavior.&lt;/p&gt;
&lt;h3 id="phase-1-look-for-big-gotchas"&gt;Phase 1: Look for Big Gotchas&lt;/h3&gt;
&lt;p&gt;When triaging performance I generally want to start big picture and focus on the following sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows Error Log&lt;/strong&gt; - How many times did I forget to check this at the beginning, only to realize there was an obvious error which was either the source of the problem or a major immediate clue? At least 10 times. Do a quick pass on this early on!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key virtualization performance counters or checks&lt;/strong&gt; - Using a hypervisor? Check (or ask the managing team to check) if the balloon driver kicked in when you had the problem, the VM was migrated between hosts, or something else unusual occurred.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL Server Error Log&lt;/strong&gt; - Have there been &lt;a href="https://kendralittle.com/2017/03/09/stack-dumps-in-sql-server-dear-sql-dba-episode-33/"&gt;stack dumps&lt;/a&gt;? Did the instance restart? Are there messages about &lt;a href="https://kendralittle.com/2016/06/16/outside-the-big-san-box-analyzing-storage-and-san-latency-in-sql-server-dear-sql-dba/"&gt;super slow storage latency&lt;/a&gt;? Again, this is always worth a quick pass early on as it can save you loads of time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do we have a ridiculous lack of resources?&lt;/strong&gt; - Spending extensive time troubleshooting performance on a 1 vCPU instance or one with 4GB of memory is going to cost way more operationally than is worth it.&lt;/li&gt;
&lt;li&gt;I like to use the free &lt;a href="https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/releases"&gt;sp_Blitz script&lt;/a&gt; from Brent Ozar Unlimited (note: I&amp;rsquo;m biased, I worked there!) to quickly check for the following. Just be sure to get used to the script so you don&amp;rsquo;t get lost in the details and can find the high level info quickly when you run it. (Again, I like to cross-check this information in a monitoring tool &amp;ndash; I&amp;rsquo;m all about triangulation and multiple tools, though.)
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bad settings which can harm performance&lt;/strong&gt; &amp;ndash; super low max memory, auto-close or auto-shrink on databases&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signs of &amp;ldquo;&lt;a href="https://www.brentozar.com/blitz/poison-wait-detected/"&gt;poison wait stats&lt;/a&gt;&amp;rdquo; which can kill performance&lt;/strong&gt; (I think I may be the person who coined that term! It me!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signs of super-slow storage from storage wait stats DMVs&lt;/strong&gt; like &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-io-virtual-file-stats-transact-sql"&gt;sys.dm_io_virtual_file_stats&lt;/a&gt; - this DMV stores an average since startup, so don&amp;rsquo;t jump to conclusions too fast, but sometimes this holds the answer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database backups / &lt;a href="https://www.brentozar.com/archive/2011/12/letters-that-get-dbas-fired/"&gt;RPO and RTO&lt;/a&gt;&lt;/strong&gt; - Although database backups / recovery models are unlikely to be the cause of your performance or availability problem, please do take the time to glance at these: because one problem is that often backups get cancelled when performance is bad in order to lighten load on the system. This can leave you exposed to MAJOR RISKS. You don&amp;rsquo;t want to be tweaking configuration and skipping backups. Well, you just don&amp;rsquo;t want to be skipping backups.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Major missing indexes&lt;/strong&gt; - SQL Server records when it thinks a nonclustered disk-based rowstore index will be useful to speed up a query in its DMVs and execution plans. Don&amp;rsquo;t assume that something in this list is the reason poor performance happens, but possibly this will inform your list of &amp;ldquo;suspects&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phase-2-narrow-down-is-it-the-infrastructure-is-it-the-workload-is-it-one-query"&gt;Phase 2: Narrow Down: Is It the Infrastructure, Is It the Workload, Is It One Query?&lt;/h3&gt;
&lt;p&gt;If I haven&amp;rsquo;t found a clear direction to go in so far and instead I&amp;rsquo;ve just ruled out the big gotchas, now I start narrowing in. Hopefully I have either a specific time period that I&amp;rsquo;m looking at where I know the problem occurred, OR I know it&amp;rsquo;s an ongoing problem which I can observe now. When it comes to anything that isn&amp;rsquo;t constant, having a specialized monitoring tool is critical.&lt;/p&gt;
&lt;p&gt;If I don&amp;rsquo;t have a specialized SQL Server Monitoring tool, I need to start sampling and capturing information without trying to put too much pressure on the system. This can be done, but you can&amp;rsquo;t do everything and once and you have to be careful &amp;ndash; so you must do a dance of watching what is running, sampling information, analyzing it, and then moving on to more samples. Data I sample or review in a monitoring tool includes things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL Server wait statistics for the impacted time - &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql"&gt;sys.dm_os_wait_stats&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-waiting-tasks-transact-sql"&gt;sys.dm_os_waiting_tasks&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;These are an invaluable tool to finding out why SQL Server is slow, but it&amp;rsquo;s quite an art to use them. You need to know what to ignore, which waits are available in different versions of SQL Server and what they mean, and which waits are more problematic than others.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s incredibly useful to have a baseline of wait statistics, either collected manually or by your monitoring system. &lt;a href="https://www.sqlservercentral.com/steps/capturing-baselines-on-sql-server-wait-statistics"&gt;Erin Stellato gives a background on wait stats and explains why here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Storage waits / samples of &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-io-virtual-file-stats-transact-sql"&gt;sys.dm_io_virtual_file_stats&lt;/a&gt; and / or performance counter information for Physical Disk (Avg Disk sec/read and write, Disk Reads/sec and Writes/sec) for the impacted time
&lt;ul&gt;
&lt;li&gt;How much are/were we using storage when there is a problem?&lt;/li&gt;
&lt;li&gt;How much storage latency do we have when there was a problem? (What latency is acceptable? As Paul Randal says, &lt;a href="https://www.sqlskills.com/blogs/paul/are-io-latencies-killing-your-performance/"&gt;everyone has their own idea of what that is &amp;ndash; here is his take&lt;/a&gt;.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Blocking and/or deadlock reports, if available
&lt;ul&gt;
&lt;li&gt;If you see lock waits in the wait statistics, blocking may have been part of the issue&lt;/li&gt;
&lt;li&gt;If you have a monitoring tool, it will help you analyze the chain of blocking and view deadlock graphs to decode which queries are involved&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Query durations and runtimes in the problem period, along with query execution plans
&lt;ul&gt;
&lt;li&gt;Both monitoring tool repositories and &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store"&gt;Query Store&lt;/a&gt; are rich sources of information for this&lt;/li&gt;
&lt;li&gt;If you don&amp;rsquo;t have either of those, you can reference &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-stats-transact-sql"&gt;sys.dm_exec_query_stats&lt;/a&gt; and related DMVs, but will need to play a guessing game about which of your suspects were running in the problem period, what their duration was then, and what execution plans they had&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="common-mistakes-and-pitfalls"&gt;Common Mistakes and Pitfalls&lt;/h2&gt;
&lt;p&gt;The biggest mistake that I&amp;rsquo;ve seen with this is that &lt;strong&gt;folks rely too much on tracing&lt;/strong&gt;. Not only can tracing slow down the SQL Server, but it slows down your triage process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have to wait for the problem to happen again&lt;/li&gt;
&lt;li&gt;Traces generate a lot of data which are time consuming to sort through and analyze&lt;/li&gt;
&lt;li&gt;You have to be cautious about the amount of things you collect to avoid causing a whole new performance problem, so it&amp;rsquo;s not uncommon to find that you weren&amp;rsquo;t tracing the right things to troubleshoot the issue after it occurs, and to need to start all over again&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My most common personal mistake is that I&amp;rsquo;ve &lt;strong&gt;forgotten to check for errors in the OS and SQL Server Logs early&lt;/strong&gt;, and missed clear indications of the source of the problem, wasting loads of time. This is easy to do in a stressful situation even when you have practice, so I recommend having a checklist or runbook for your team to use when triaging.&lt;/p&gt;
&lt;p&gt;Another common issue is that &lt;strong&gt;not all SQL Server performance counters are useful&lt;/strong&gt;, and &lt;a href="https://www.brentozar.com/archive/2013/07/on-bobcats-per-100-orders-and-other-spurious-metrics/"&gt;some have persistent myths and misinformation to be aware of&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I&amp;rsquo;ve found that one of the hardest problems to identify is parameter sniffing&lt;/strong&gt;. It&amp;rsquo;s good to be familiar with this in advance if you need to troubleshoot performance in SQL Server. A great resource on this is Erland Sommarskog&amp;rsquo;s &lt;a href="http://www.sommarskog.se/query-plan-mysteries.html"&gt;Slow in the Application, Fast in SSMS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="how-is-this-evolving-and-what-does-the-future-look-like"&gt;How Is This Evolving, and What Does the Future Look Like?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;One of the most exciting pieces of tooling introduced into SQL Server regarding performance tuning recently is &lt;a href="https://kendralittle.com/2018/03/01/why-i-love-the-automatic-plan-correction-auto-tuning-feature/"&gt;Automatic Plan Correction&lt;/a&gt;&lt;/strong&gt;. This requires the use of Query Store and it helps identify when queries are sometimes fast and sometimes slow. In other words it can help with identifying that tricky problem of parameter sniffing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may use this in an advisory mode, or let it test freezing different plans for you in production&lt;/li&gt;
&lt;li&gt;Note that &amp;ldquo;corrections&amp;rdquo; are intended as temporary fixes: for long term performance, queries that are &amp;ldquo;corrected&amp;rdquo; likely need either query tuning and/or index tuning&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Automatic Index Tuning is available in Azure PAAS editions&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;m not crazy about trusting SQL Server&amp;rsquo;s missing index suggestions &amp;ndash; I look at them but take them as a suggestion to look at the related queries directly and do my own analysis, as they&amp;rsquo;re often oversimplified.&lt;/li&gt;
&lt;li&gt;I do NOT trust &lt;a href="https://kendralittle.com/2017/03/08/overindexing-missing-index-dmvs-and-the-database-tuning-advisor/"&gt;ye olde Database Tuning Advisor&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;But automatic index tuning is an interesting feature and it involves an element of testing.&lt;/li&gt;
&lt;li&gt;I haven&amp;rsquo;t personally looked into this much, but I&amp;rsquo;m curious about it, and I can see it working well on the right workloads, probably workloads with relatively small data sizes.&lt;/li&gt;
&lt;li&gt;Automatic index tuning does present interesting challenges in terms of how teams want to manage schema in source control and what indexes they want to deploy to a new workload if using &lt;a href="https://www.brentozar.com/archive/2011/06/how-design-multiclient-databases/"&gt;a single-tenant-per-database architecture&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;APIs for Customization from Monitoring tools&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Did that deployment/maintenance/configuration change we did yesterday cause a problem? When exactly did it happen, anyway?&amp;rdquo; Figuring that out has always been a toughie.&lt;/li&gt;
&lt;li&gt;One of the cool things that SQL Monitor has done is to add an &lt;a href="https://documentation.red-gate.com/sm/api/annotations"&gt;API for annotations&lt;/a&gt; so that teams can track significant events on the graph of performance metrics.&lt;/li&gt;
&lt;li&gt;This can be automated to happen right away when an event occurs, or it can be used by team members to note times of interest, perhaps when triaging performance and noting times when a problem occurred.&lt;/li&gt;
&lt;li&gt;As DBAs merge more into platform teams and/or combine with development teams, the use of &lt;a href="https://documentation.red-gate.com/sm/api"&gt;APIs to both manage alerts&lt;/a&gt; and the ability &lt;a href="https://documentation.red-gate.com/sm10/configuring-sql-monitor/setting-up-webhook-notifications/custom-webhook-messages"&gt;customize how alerts are delivered&lt;/a&gt; will only increase, along with other custom features enabling teams to customize their responses to incidents. (Again, I work for Redgate, so I&amp;rsquo;m biased on my choice of tooling and examples.)&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Why Re-teaming Is Good</title><link>https://kendralittle.com/2020/03/13/re-teaming-is-good-heres-why/</link><pubDate>Fri, 13 Mar 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/03/13/re-teaming-is-good-heres-why/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: This post is based on an &lt;a href="https://www.sqlservercentral.com/editorials/self-selection-reteaming-its-not-crazy-its-the-future"&gt;editorial I originally published over at SQL Server Central&lt;/a&gt;.
&lt;/div&gt;
&lt;p&gt;Years ago, I worked on a fabulous team of eight database administrators&lt;/p&gt;
&lt;p&gt;We supported more than a hundred developers who worked in an agile fashion. When I first joined the DBA team, we had a shared on-call rotation, but each DBA specialized in a certain area of the environment and regularly met with the development teams working on that area. DBA specializations rarely shifted.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-13-03-2020_12-03-05.jpg"
alt="A view of many different pairs of shoes on people&amp;#39;s legs who are sitting on the edge of a wall." width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="over-time-this-created-significant-stressors"&gt;Over Time, This Created Significant Stressors&lt;/h2&gt;
&lt;p&gt;Covering on-call for some areas became quite difficult in times of rapid change. It became impossible for someone to be out of the office for an extended period without delaying releases. When we got to the point that we had to decide whether or not to escalate a critical issue to someone who was attending a funeral, it was clearly time for a change.&lt;/p&gt;
&lt;h2 id="to-gain-flexibility-the-dba-team-decided-to-regularly-rotate-positions"&gt;To Gain Flexibility, the DBA Team Decided to Regularly Rotate Positions&lt;/h2&gt;
&lt;p&gt;Not everyone was thrilled. We each felt attached to the environment we supported: like a garden we had faithfully tended for years, it was hard to let it go! This made the transition a bit tough, especially at first.&lt;/p&gt;
&lt;p&gt;Over time, we found that regularly rotating specializations had many benefits for our group. The most wonderful improvement was that it made it possible for team members to fully disconnect while they were off work, as other team members not only had deep technical familiarity with an area, but also our developers were used to partnering with more of us and everyone could adapt more easily.&lt;/p&gt;
&lt;h2 id="fast-forward-to-today-now-i-work-at-redgate"&gt;Fast Forward to Today: Now I Work at Redgate&lt;/h2&gt;
&lt;p&gt;When I joined Redgate I was intrigued to learn that our Product Development teams run a self-selective re-teaming process across the entire division. Re-teaming just took place at Redgate in January 2020 for the second year in a row. Because it is at a larger scale than eight people, Redgate’s re-teaming model gives people the option to have a say on whether it is time for a change or not (rather than only enforcing rotation).&lt;/p&gt;
&lt;p&gt;Self-selecting reteaming is used at Redgate for multiple reasons, which I’ve shamelessly stolen from an internal post written by Redgate’s own &lt;a href="https://medium.com/ingeniouslysimple/team-self-selection-without-the-anxiety-be5a1478c484"&gt;Chris Smith&lt;/a&gt; to share with you. Reteaming….&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Realigns team size and purpose to reflect the larger organizational strategy for the year&lt;/li&gt;
&lt;li&gt;Gives engineers autonomy based on the principle that people will be most engaged and motivated if they have agency regarding what they work on&lt;/li&gt;
&lt;li&gt;Spreads knowledge, best practices, and innovation throughout teams, as people bring techniques, skills, and insights along with them from their prior work&lt;/li&gt;
&lt;li&gt;Enables personal development&lt;/li&gt;
&lt;li&gt;Reflects the recommendations of thought leaders, who champion this collaborative approach as an increasingly common characteristic of high-performing software development organizations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="re-teaming-encourages-good-documentation-habits"&gt;Re-teaming Encourages Good Documentation Habits&lt;/h2&gt;
&lt;p&gt;This week I realized something obvious: if you&amp;rsquo;re a developer who has been working on a productivity tool like SQL Prompt and you move to working on a tool related to version control and automation, there are certain things you wouldn&amp;rsquo;t necessarily know about your customers. For example, most customers in financial services and healthcare can&amp;rsquo;t or won&amp;rsquo;t use SQL Authentication. There are many things like this.&lt;/p&gt;
&lt;p&gt;However, this isn&amp;rsquo;t a blocker to re-teaming. Instead, realizing this helped me understand that I can help improve our customer profiles to make these types of requirements and preferences more clear to everyone.&lt;/p&gt;
&lt;p&gt;Reteaming helps surface &amp;ldquo;tribal knowledge&amp;rdquo; and help make it clearer for everyone.&lt;/p&gt;
&lt;h2 id="although-change-can-be-tough-i-believe-that-well-increasingly-find-reteaming-practices-popping-up-in-engineering-teams-everywhere"&gt;Although Change Can Be Tough, I Believe That We&amp;rsquo;ll Increasingly Find Reteaming Practices Popping Up in Engineering Teams Everywhere&lt;/h2&gt;
&lt;p&gt;And in my experience, it’s a good thing.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about Redgate’s use of self-selecting reteaming, check out the “&lt;a href="https://open.spotify.com/episode/2yldp7o6KVJaCmsszhGRwc?si=dwsFIv15QJygse7DjqqRhQ"&gt;Dynamic Reteaming (with Heidi Helfand&lt;/a&gt;)” episode of the Ingeniously Simple Podcast.&lt;/p&gt;</description></item><item><title>Altering an Indexed View in SQL Server Drops All Indexes</title><link>https://kendralittle.com/2020/03/02/altering-an-indexed-view-in-sql-server-drops-all-indexes/</link><pubDate>Mon, 02 Mar 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/03/02/altering-an-indexed-view-in-sql-server-drops-all-indexes/</guid><description>&lt;p&gt;I learned an interesting thing about ALTER VIEW behavior in SQL Server when applied to indexed views. This is covered in the product documentation, but it&amp;rsquo;s not something I would have expected.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ALTER VIEW can be applied to indexed views; however, ALTER VIEW unconditionally drops all indexes on the view.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-view-transact-sql"&gt;ALTER VIEW documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-02-03-2020_14-25-06.jpg"
alt="photo of a book cover that reads &amp;#39;Something Needs to Change&amp;#39;" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;When I first heard about this behavior, it sounded like a bug to me: why should an alteration like adding a column to a view remove all the indexes?&lt;/p&gt;
&lt;p&gt;A colleague of mine at Redgate wondered: is the behavior the same with the new CREATE OR ALTER syntax as it is with just plain ALTER? (Spoiler: &lt;a href="https://gist.github.com/LitKnd/6b6d58b819ff38ff0d6277bb8389ca29"&gt;I tested and it is the same&lt;/a&gt;: CREATE OR ALTER also drops all indexes on the view.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One note&lt;/strong&gt;: if you are using Redgate tooling to commit your database objects to version control, never fear: it handles this for you and will automatically put the indexes back on your indexed views if you alter them! This is true both for SQL Source Control and SQL Change Automation. Just be aware that behind the scenes the indexes must effectively be recreated to implement this change, so if large tables are involved in the view definition, deployment time will be impacted.&lt;/p&gt;
&lt;h2 id="this-behavior-makes-some-sense-when-i-think-about-how-indexed-views-are-implemented"&gt;This Behavior Makes &lt;em&gt;Some&lt;/em&gt; Sense When I Think About How Indexed Views Are Implemented&lt;/h2&gt;
&lt;p&gt;When you create an index on a view (we&amp;rsquo;re talking views using classic disk-based tables here), it materializes the view &amp;ndash; in other words, it stores the data as if it is a table. That data is stored in rows on 8KB pages. These pages can fill up. So if you add a column to a view, just like adding a column which requires a size-of-data operation to a table, the database engine needs to rewrite those pages to add the new column to each and every row (depending on datatypes and nullability, etc etc).&lt;/p&gt;
&lt;p&gt;Also, it&amp;rsquo;s quite possible that when altering an indexed view, the alteration makes the view no longer adhere to the &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/views/create-indexed-views?view=sql-server-ver15"&gt;many rules required for indexed views&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After thinking about this, I can understand why if you allow ALTER VIEW, the simplest way to implement that against an indexed view is to make it the user&amp;rsquo;s problem to ensure that indexes can be re-created after altering a view.&lt;/p&gt;
&lt;h2 id="however-i-personally-wonder-if-alter-view-should-even-work-for-indexed-views"&gt;However, I Personally Wonder If ALTER VIEW Should Even Work for Indexed Views&lt;/h2&gt;
&lt;p&gt;This is one of those little niche behaviors that strikes me as problematic. From a user perspective, I&amp;rsquo;d personally rather that ALTER VIEW simply failed for indexed views and notified me that to change an indexed view, I need to drop the indexes, alter the view, then recreate the indexes which I need. Although that&amp;rsquo;s more work to me as a user, it helps me understand that this is not necessarily a cheap or low risk operation, and it reduces the risk of me accidentally deploying code that un-indexes a view which might be critical to performance.&lt;/p&gt;
&lt;p&gt;However, this ship has sailed: the behavior is documented and established and unlikely to change in the SQL Server Engine anytime soon.&lt;/p&gt;
&lt;h2 id="want-to-see-a-demo"&gt;Want to See a Demo?&lt;/h2&gt;
&lt;p&gt;Check out &lt;a href="https://www.erikdarlingdata.com/2019/09/be-careful-when-you-alter-indexed-views/"&gt;this fantastic video by Erik Darling where he discusses and demos this behavior&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Come Work with Me! Be a Sales Engineer for Redgate</title><link>https://kendralittle.com/2020/02/21/come-work-with-me-be-a-sales-engineer-for-redgate/</link><pubDate>Fri, 21 Feb 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/02/21/come-work-with-me-be-a-sales-engineer-for-redgate/</guid><description>&lt;p&gt;Redgate is growing, and we have some fresh, new open positions around the world which would be a great fit for SQL Server developers or DBAs who would like to transition to a customer-facing role and develop expertise in Redgate&amp;rsquo;s solutions for Compliant Database DevOps. Here are the listings and locations for three of these roles:&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-21-02-2020_19-22-18.jpg"
alt="A &amp;#39;now hiring&amp;#39; sign"&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.red-gate.com/our-company/careers/current-opportunities/sales-engineer"&gt;Sales Engineer - Cambridge, UK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.red-gate.com/our-company/careers/current-opportunities/pre-sales-engineer-pasadena-ca"&gt;Pre-Sales Engineer – Pasadena, CA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.red-gate.com/our-company/careers/current-opportunities/pre-sales-engineer-austin-tx"&gt;Sales Engineer – Austin, TX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a DevOps Advocate, the Sales Engineering team is one of my favorite groups to work with at Redgate. These folks get to learn &lt;em&gt;all&lt;/em&gt; about database DevOps, and they get to show clients the possibilities for how they can better develop and deliver database changes, as well as how to better protect their data in the software development process.&lt;/p&gt;
&lt;p&gt;But the Sales Engineers aren&amp;rsquo;t only intelligent. Our Sales Engineering team is a group of kind, smart people who are just plain fun to spend time with. Whenever I&amp;rsquo;m on a call or a webinar with one of the SEs, we work as a team and we have a great time figuring out how to solve problems. Joining our Sales Engineering team means joining one of the most respected and well-known teams inside Redgate.&lt;/p&gt;
&lt;h2 id="one-note-about-sales-at-redgate"&gt;One Note About Sales at Redgate&lt;/h2&gt;
&lt;p&gt;Redgate practices ethical selling. Depending on your life experience, the words &amp;ldquo;ethical selling&amp;rdquo; may look a bit like an oxymoron. However, I&amp;rsquo;ve been working with our sales teams at Redgate for more than a year and I can attest that we really do work our hardest to make sure that we only recommend solutions for the client which fit the team&amp;rsquo;s needs and which will help the client succeed. There&amp;rsquo;s no &amp;ldquo;vapor ware&amp;rdquo; in this job, only helping people find a solution which empowers them to work more effectively as a team, be more productive, and deliver value for their organization more rapidly.&lt;/p&gt;
&lt;h2 id="dont-know-devops"&gt;Don&amp;rsquo;t Know DevOps?&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re knowledgeable about databases and are interested in developing expertise in Database DevOps (but aren&amp;rsquo;t there yet), please feel free and empowered to apply! While it&amp;rsquo;s terrific to find an applicant who is well versed in it all, this is one of those &amp;ldquo;unicorn&amp;rdquo; jobs in my experience where strong experience in a few of the needed areas is what is needed, as there&amp;rsquo;s not exactly a huge pool of people who tick &lt;em&gt;all&lt;/em&gt; the boxes.&lt;/p&gt;
&lt;h2 id="if-youre-interested-in-the-job-please-use-one-of-the-links-above-to-apply"&gt;If You&amp;rsquo;re Interested in the Job, Please Use One of the Links Above to Apply&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to specify me as the person who referred you on the application form, that&amp;rsquo;d be lovely &amp;ndash; and full disclosure, I might get a bonus if you get hired. If you don&amp;rsquo;t feel like listing me, that&amp;rsquo;s OK too, we&amp;rsquo;d still love to hear from you.&lt;/p&gt;</description></item><item><title>I Can Do Better, We Can Do Better, Let's Do Better</title><link>https://kendralittle.com/2020/02/13/i-can-do-better-we-can-do-better-lets-do-better/</link><pubDate>Thu, 13 Feb 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/02/13/i-can-do-better-we-can-do-better-lets-do-better/</guid><description>&lt;p&gt;In the past week or so, the Microsoft Data Platform community has begun having a discussion about inclusivity, both on Twitter and across community blog posts.&lt;/p&gt;
&lt;p&gt;This conversation began when a member of the community shared their story about being repeatedly mis-gendered and additionally feeling excluded, unwelcome, and hurt at a series of community events.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-13-02-2020_22-09-01.jpg"
alt="Graffiti reading: let&amp;#39;s love our community" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Historically the legacy SQL Server community has had quite visible support for Women in Technology, but has not shifted broadly/overall to a public focus on larger Diversity and Inclusion issues. There have been efforts to be more inclusive to people of color and members of the LGBTQ community, but these efforts have have not been nearly as visible or &amp;ldquo;popular&amp;rdquo; within the community as the efforts to support WIT.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t write this in an accusatory way, only to describe the state of things as I see them. I have not worked to change this, and as a community member I share in the responsibility for the problem I see.&lt;/p&gt;
&lt;h2 id="this-past-week-i-have-seen-more-care-and-concern-from-community-members-over-this-issue-than-i-expected"&gt;This Past Week I Have Seen More Care and Concern from Community Members Over This Issue Than I Expected&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve seen many comments from people saying that they want to learn to be more inclusive, and I&amp;rsquo;ve also seen folks asking for advice on how to speak and act in ways that will help make everyone feel welcome.&lt;/p&gt;
&lt;p&gt;This pattern of asking how to do better is what makes me the happiest, because I do need help to learn to be inclusive by default, and to recognize when I am making a mistake without realizing it. I see that I&amp;rsquo;m not alone in recognizing this and I appreciate others who are making it a known pattern to ask for help in this way.&lt;/p&gt;
&lt;h2 id="here-is-an-example-i-thought-about-this-week-from-my-own-life"&gt;Here Is an Example I Thought About This Week from My Own Life&lt;/h2&gt;
&lt;p&gt;Years ago I began a job as a contractor (V-dash, holla!) at Microsoft. At the time there was a bit of an &amp;ldquo;outsider&amp;rdquo; feel to being a contractor, but I didn&amp;rsquo;t mind, I got to work on cool stuff, and I liked my fellow contractors just as well as I liked the full time employees.&lt;/p&gt;
&lt;p&gt;One office over from where I sat was another contractor who happened to be transgender. We didn&amp;rsquo;t work on the same team, so we were never in the same meetings, but we passed each other in the hallway plenty. I never said &amp;ldquo;hi.&amp;rdquo; I never went out of my way to smile. I never said, &amp;ldquo;hey, do you want to grab lunch?&amp;rdquo; Looking back, there was plenty of evidence that my coworker felt unwelcome, isolated, and alone, and by doing nothing I simply added to that problem.&lt;/p&gt;
&lt;p&gt;What I &lt;em&gt;should&lt;/em&gt; have done was to be friendly and welcoming to my colleague, even though we weren&amp;rsquo;t on the same team. I should have introduced myself. I should have smiled in the hall, even if I&amp;rsquo;m always super awkward smiling at people I don&amp;rsquo;t know (insecurity, hi, it me). I should have asked if they liked what they were working on: like I did of plenty of other folks who were on other teams.&lt;/p&gt;
&lt;p&gt;If &lt;em&gt;I&lt;/em&gt; felt like I was a bit of an &amp;ldquo;outsider&amp;rdquo; because I was a contractor, I can hardly imagine how my colleague felt.&lt;/p&gt;
&lt;p&gt;I did not realize this in any way until this week.&lt;/p&gt;
&lt;h2 id="ive-learned-a-lot-this-week"&gt;I&amp;rsquo;ve Learned a Lot This Week&lt;/h2&gt;
&lt;p&gt;I can&amp;rsquo;t go back and redo my past behavior, but I can do better now and in the future. I can ask others to help me recognize when I can improve. I can listen. And I think we as a community can do better as well. I am regretful that someone was hurt, but I am glad that we are having this conversation. Growth is usually not comfortable, but it is important.&lt;/p&gt;</description></item><item><title>Protect Your Prod Databases in Azure DevOps / TFS: Three Control Points</title><link>https://kendralittle.com/2020/02/05/protect-your-prod-databases-in-azure-devops-tfs-three-control-points/</link><pubDate>Wed, 05 Feb 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/02/05/protect-your-prod-databases-in-azure-devops-tfs-three-control-points/</guid><description>&lt;p&gt;When implementing any kind of automation for database deployments, it&amp;rsquo;s important to implement safeguards for your production environment. This is needed even in the best conditions when team members collaborate well and there is a high level of trust, for a very simple reason: accidents happen easily!&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-05-02-2020_18-22-15-300x300.jpg"
alt="A photograph of industrial pipes" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;As a person who has accidentally destroyed quite a lot of things VERY RAPIDLY with automation😱, I am a fan of adding protection around production environments to lower risk for everyone, including myself.&lt;/p&gt;
&lt;p&gt;On the other hand, it&amp;rsquo;s also desirable to empower team members to be able to quickly build and experiment with automation in other environments. It&amp;rsquo;s best to not lock down more than you need to.&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;ll give a quick overview of three control points which help protect your production databases when working with Azure DevOps Server/Services (or legacy Team Foundation Services). The controls I&amp;rsquo;m discussing here apply to SQL Server instances where you are deploying changes with self-hosted &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents"&gt;agents&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s more than one way to do these things, so if you&amp;rsquo;ve got thoughts about your favorite alternatives, I&amp;rsquo;d love to hear about them in the comments.&lt;/p&gt;
&lt;h2 id="1-control-who-can-create-new-pipelines-against-production-instances"&gt;1. Control Who Can Create New Pipelines Against Production Instances&lt;/h2&gt;
&lt;p&gt;While it&amp;rsquo;s useful to let folks create new pipelines and edit them against all sorts of development, test, or QA resources, not everyone should be able to create a pipeline, point it to an existing production database, and deploy changes to it.&lt;/p&gt;
&lt;p&gt;One simple way to manage this is to create one or more &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/pools-queues"&gt;agent pools&lt;/a&gt; for production SQL Server instances and use the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/organizations/security/about-security-roles"&gt;security properties&lt;/a&gt; on the agent pool to limit who can create pipelines using that agent pool. For those who need to see the progress of pipelines/monitor deployments, there is a &amp;lsquo;Reader&amp;rsquo; role available.&lt;/p&gt;
&lt;p&gt;This could also be done with &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/release/deployment-groups"&gt;deployment groups&lt;/a&gt; for parallel execution.&lt;/p&gt;
&lt;h2 id="2-control-what-the-agent-can-do"&gt;2. Control What the Agent Can Do&lt;/h2&gt;
&lt;p&gt;When you install a self-hosted agent, you are prompted to configure not only which agent pool it uses, but also which account the agent will run under. If you wish for that agent to only be able to deploy to one SQL Server, you may choose to use an account which you have granted only permissions for that SQL Server instance.&lt;/p&gt;
&lt;p&gt;In other words, if you are concerned about the agent being used to communicate with other SQL Server instances across the network in your production environment, you have the ability to control this by using an account which only has permissions granted against the SQL Server instance of your choice.&lt;/p&gt;
&lt;h2 id="3-control-what-can-be-done-within-an-existing-release-pipeline"&gt;3. Control What Can Be Done Within an Existing Release Pipeline&lt;/h2&gt;
&lt;p&gt;Pipelines are quite flexible and there are many things you can do with them in terms of gating and approvals. Two very powerful controls which you may choose to configure right away for pipelines with production targets are&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure who can run vs edit vs view a pipeline:&lt;/strong&gt; &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/policies/permissions"&gt;Pipeline security&lt;/a&gt; can be configured to allow people to interact with an existing pipeline in many different ways – for instance some users/groups perhaps should be able to execute the pipeline but not edit the pipeline definition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure approvals within the pipeline&lt;/strong&gt;: Stages may be edited to set approvals. An example with Redgate tooling is that you might create one stage to create a release artifact for a production change, then another stage which performs the deployment of that release artifact. You might choose to &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/release/approvals/approvals?"&gt;add an approval step at the entry to the deployment stage&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="its-ok-to-start-slowly"&gt;It&amp;rsquo;s OK to Start Slowly&lt;/h2&gt;
&lt;p&gt;If this is a bit overwhelming, remember that you don&amp;rsquo;t have to automate everything at once, and in fact it&amp;rsquo;s preferable to have a strong foundation for automation. The first step is to identify the current pain points and constraints for your team and start from there. If your database code isn&amp;rsquo;t yet in version control, beginning there is very likely the first step. If provisioning dev, test, or pre-production environments is slow and cumbersome, working on automating provision and deployments there will help increase your velocity. But when it does come time to begin automating deployments to production environments, do take the time to examine the available safeguards and implement the right controls for your organization.&lt;/p&gt;</description></item><item><title>High Availability Options for SQL Server 2008 in an Azure VM: A #sqlhelp Story</title><link>https://kendralittle.com/2020/02/01/high-availability-options-for-sql-server-2008-in-an-azure-vm-a-sqlhelp-story/</link><pubDate>Sat, 01 Feb 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/02/01/high-availability-options-for-sql-server-2008-in-an-azure-vm-a-sqlhelp-story/</guid><description>&lt;p&gt;I &lt;a href="https://twitter.com/Kendra_Little/status/1223212966293704704"&gt;asked a question on Twitter&lt;/a&gt; yesterday: &amp;ldquo;If running SQL Server 2008 in an Azure VM (no SQL upgrade possible, extended support in place), is the best option for high availability Database Mirroring? Or something else I am not thinking of? #sqlhelp&amp;rdquo;&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-01-02-2020_18-00-04.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="the-community-response"&gt;The Community Response&lt;/h2&gt;
&lt;p&gt;And check out the magic of the &lt;a href="https://twitter.com/hashtag/sqlhelp?src=hashtag_click&amp;amp;f=live"&gt;sqlhelp hash tag&lt;/a&gt;, I got loads of answers! So many that I&amp;rsquo;m actually selecting a few here for the purposes of keeping this post readable. First, &lt;a href="https://twitter.com/SqlrUs"&gt;John Morehouse&lt;/a&gt; , a consultant who does a lot of great work in the cloud and on-prem helped me figure out what would be needed for clustering (which isn&amp;rsquo;t something you can do simply with this version in an Azure VM)&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I belive you could also cluster it but you’ll need SIOS for the storage. I think. DisclaImer: I’ve never tried it. Mirroring should work as well and might be simpler. #sqlhelp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="microsofts-input"&gt;Microsoft&amp;rsquo;s Input&lt;/h2&gt;
&lt;p&gt;I also got input from two folks at Microsoft, &lt;a href="https://twitter.com/ZamoraO"&gt;Oscar Zamora&lt;/a&gt; and &lt;a href="https://twitter.com/banerjeeamit"&gt;Amit Banerjee&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SIOS, mirroring or VM replication/Azure site recovery #sqlhelp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="additional-perspectives"&gt;Additional Perspectives&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/GlennAlanBerry"&gt;Glenn Berry&lt;/a&gt; chimed in: he is also a consultant and specializes in topics like high availability and performance.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As others have said, Failover clustering using SIOS for the shared storage. Instance-level protection, that would be easier to maintain than DBM. #sqlhelp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Other folks responded as well. It can be so useful to get multiple perspectives on a topic, and I&amp;rsquo;m continuously amazed at how helpful folks in the Microsoft Data Platform community are when they can help out with a question.&lt;/p&gt;
&lt;p&gt;Thanks to everyone who helped me out!&lt;/p&gt;</description></item><item><title>A First Look at the Redgate Hybrid Model for SQL Source Control and SQL Change Automation (Video)</title><link>https://kendralittle.com/2020/01/25/do-it-live-a-first-look-at-redgates-hybrid-model-for-sql-source-control-and-sql-change-automation-video/</link><pubDate>Sat, 25 Jan 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/01/25/do-it-live-a-first-look-at-redgates-hybrid-model-for-sql-source-control-and-sql-change-automation-video/</guid><description>&lt;h2 id="about-this-video"&gt;About This Video&lt;/h2&gt;
&lt;p&gt;In this 70 minute livestream recording, I kick the tires of a fresh new Azure DevOps demo environment showing Redgate&amp;rsquo;s Hybrid Model for SQL Source Control and SQL Change Automation.&lt;/p&gt;
&lt;h2 id="video"&gt;Video&lt;/h2&gt;
&lt;p&gt;To skip watching me installing ZoomIt in the new demo environment, start at around 6 minutes.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/D6cOY_k4RSU?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Controlling Who Commits Code to a Given Database Schema in Git with Azure DevOps</title><link>https://kendralittle.com/2020/01/18/controlling-who-commits-code-to-a-given-database-schema-in-git-with-azure-devops/</link><pubDate>Sat, 18 Jan 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/01/18/controlling-who-commits-code-to-a-given-database-schema-in-git-with-azure-devops/</guid><description>&lt;p&gt;One of most the fun things about working as an Advocate at Redgate is getting to help clients determine their preferred workflow for database DevOps.&lt;/p&gt;
&lt;p&gt;Teams often have unique requirements and are using different combinations of tooling, so figuring out the best way to accomplish what they need typically involves leveraging what I already know, collaborating with my coworkers and the client to generate ideas, researching and prototyping solutions, and then getting feedback from everyone.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-18-01-2020_00-18-02.jpg"
alt="Overhead view of two people working on laptops" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="moving-from-monolith-to-microservices"&gt;Moving from Monolith to Microservices&lt;/h2&gt;
&lt;p&gt;One pattern which can enable this move is to at first increase the use of schemas within the existing large legacy database, and begin to document and understand dependencies between different parts of the codebase. Over time, the goal is to reduce dependencies and to begin to move portions of the database out from the large legacy database and into their own data stores. The schemas help clarify &amp;lsquo;ownership&amp;rsquo; of code with minimal initial impact to performance and no need for initial data movement.&lt;/p&gt;
&lt;h2 id="limiting-who-can-commit-to-each-schema"&gt;Limiting Who Can Commit to Each Schema&lt;/h2&gt;
&lt;p&gt;In other words, if team Fruitbats owns a schema which exists for the Fruitbats service, members of the Cheeseweasel team shouldn&amp;rsquo;t just go making changes to those objects. Instead, they need to talk to the Fruitbats team and discover what the best way is to accomplish what they need. At the same time, it&amp;rsquo;s valuable for team members to be able to see the code for all objects to support the existing legacy codebase.&lt;/p&gt;
&lt;p&gt;I thought about a couple of different options in thinking through this, including things like using multiple projects, using a branching strategy, or figuring out some way to run checks in pre-commit hooks with Git.&lt;/p&gt;
&lt;h2 id="heres-what-i-would-do"&gt;Here&amp;rsquo;s What I Would Do&lt;/h2&gt;
&lt;p&gt;After consideration, the approach which I think is the simplest, but which has the most benefits, is to keep all objects in the database in a single project and use Pull Requests (PRs) with automatic reviewers to ensure the right changes are being made.&lt;/p&gt;
&lt;p&gt;This is simple to set up with a combination of Azure DevOps and Redgate&amp;rsquo;s SQL Source Control tooling, because SQL Source Control uses an object&amp;rsquo;s schema name as part of the file name.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an overview of the setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies"&gt;branch policy&lt;/a&gt; protects master and requires a PR to complete a merge&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies#automatically-include-code-reviewers"&gt;Automatic reviewers&lt;/a&gt; are set up
&lt;ul&gt;
&lt;li&gt;Establish a user or group with ownership over each schema, and set up a rule so that if any files in that schema are changed in a PR, the group or user is added to the PR. It can&amp;rsquo;t pass until they review it (or someone with permission to override makes it so).&lt;/li&gt;
&lt;li&gt;Since SQL Source Control places the schema name at the beginning of file names, the filter for each schema can be as simple as something like: */fruitbats.*&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Automation can further automatically run a build of code and run tests against the code when the PR is created, which can do things like ensure that new cross-schema dependencies are not introduced&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like this approach because while it ensures that the teams owning a schema will always be in the loop on a change, it is still flexible: there may be times when it is desirable to have a single person contribute changes to multiple schemas. This allows that without the need for permissions to be reconfigured, and it even gives a place for the owners of all those schemas to have visibility and input on the change early in the process.&lt;/p&gt;
&lt;h2 id="in-other-words-this-was-simpler-than-i-thought"&gt;In Other Words, This Was Simpler Than I Thought&lt;/h2&gt;
&lt;p&gt;The approach here can be a simple modification to an implementation of the &lt;a href="https://kendralittle.com/2020/01/10/why-i-like-the-release-flow-branching-strategy-with-git-for-database-devops/"&gt;Azure DevOps Release Flow branching strategy&lt;/a&gt; I wrote about last week: it&amp;rsquo;s a way to use feature branches with automatic reviewers. While there are certainly other ways to solve this problem, this workflow fits many teams and is also quite simple to implement and maintain.&lt;/p&gt;</description></item><item><title>Why I Like the Release Flow Branching Strategy with Git for Database DevOps</title><link>https://kendralittle.com/2020/01/10/why-i-like-the-release-flow-branching-strategy-with-git-for-database-devops/</link><pubDate>Fri, 10 Jan 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/01/10/why-i-like-the-release-flow-branching-strategy-with-git-for-database-devops/</guid><description>&lt;p&gt;When people begin applying &lt;a href="http://www.donovanbrown.com/post/what-is-devops"&gt;DevOps&lt;/a&gt; principles to database development using Redgate tooling, often one of the first steps in the process involves getting database code into version control. Questions naturally come up about how to manage the flow of changes to database objects from development into production once changes begin occurring.&lt;/p&gt;
&lt;p&gt;When using Git for version control, &lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell"&gt;branches&lt;/a&gt; are a huge help when it comes to managing this flow.&lt;/p&gt;
&lt;p&gt;But how do you use branches? It&amp;rsquo;s helpful to pick a strategy. There are &lt;em&gt;many&lt;/em&gt; fine Git branching strategies out there, things like GitFlow and GitHub Flow and more &amp;ndash; enough that it&amp;rsquo;s overwhelming to learn about these when you are just starting out.&lt;/p&gt;
&lt;p&gt;The strategy that I recommend for folks who are starting out with database DevOps and Git is the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/learn/devops-at-microsoft/release-flow"&gt;Azure DevOps team Release Flow model&lt;/a&gt; with dedicated development databases. (Why dedicated development databases? &lt;a href="https://www.troyhunt.com/unnecessary-evil-of-shared-development/"&gt;Read more here&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="why-the-azure-devops-release-flow-model-fits-databases-well"&gt;Why the Azure DevOps Release Flow Model Fits Databases Well&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Topic / feature branches provide a place for experimentation&lt;/li&gt;
&lt;li&gt;Pull requests provide communication, feedback, and review &amp;ndash; a prime collaboration point for developers and DBAs for many teams&lt;/li&gt;
&lt;li&gt;Code can be merged into the main code line without being deployed automatically (for databases, where rollbacks are often anything &lt;em&gt;but&lt;/em&gt; straightforward, immediate deployment isn&amp;rsquo;t always grand)&lt;/li&gt;
&lt;li&gt;Releasing at sprint milestones using a branch created for deployment often makes the most sense&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Further, the release flow model can support both small and large teams.&lt;/p&gt;
&lt;h2 id="i-drew-a-diagram"&gt;I Drew a Diagram&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/release-flow.png"
alt="Diagram showing the Release Flow branching strategy"&gt;
&lt;/figure&gt;
&lt;h2 id="sometimes-other-models-make-sense"&gt;Sometimes Other Models Make Sense&lt;/h2&gt;
&lt;p&gt;For instance, for those who have implemented a microservices model with robust automated testing in place, it may be more suitable to do something like a modification of the GitHub flow branching strategy.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s not the case for most folks &amp;ndash; most folks have databases which are more complex, with cross-database queries and downstream dependencies galore. For these more ordinary databases, the Azure DevOps Release Flow model is a really great place to begin.&lt;/p&gt;</description></item><item><title>Why I'm Learning Git via the Command Line Interface</title><link>https://kendralittle.com/2020/01/03/why-im-learning-git-via-the-command-line-interface/</link><pubDate>Fri, 03 Jan 2020 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2020/01/03/why-im-learning-git-via-the-command-line-interface/</guid><description>&lt;p&gt;I&amp;rsquo;ve learned a bit about Git in the last year: I&amp;rsquo;m now quite comfortable creating and managing Git Repos in Azure DevOps. I frequently do demos with SQL Change Automation and SQL Source control with Git on &lt;a href="https://www.youtube.com/playlist?list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc"&gt;Redgate&amp;rsquo;s YouTube channel&lt;/a&gt;, and &lt;a href="https://kendralittle.com/2019/11/27/my-git-cli-cheat-sheet/"&gt;I&amp;rsquo;ve published a Git Cheat Sheet for the Command Line Interface&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Git-Icon-1788C.png"
alt="Git icon" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="my-git-learning-journey"&gt;My Git Learning Journey&lt;/h2&gt;
&lt;p&gt;I love learning Git now: I&amp;rsquo;m very comfortable with a small set of core commands which empower me to get a lot done and I&amp;rsquo;m able to regularly add new bits of knowledge into my repertoire.&lt;/p&gt;
&lt;p&gt;I was interested in learning Git before, and I tried and failed to get started learning more than once. Each time, part of the problem was that I tried to use graphical tooling which I thought would make the whole thing simpler, but which I found to be difficult to start using – and also prone to quickly getting me into complex situations which I didn&amp;rsquo;t understand.&lt;/p&gt;
&lt;p&gt;A big differentiator to me finally learning Git was embracing the built-in command line interface (CLI).&lt;/p&gt;
&lt;h2 id="why-the-cli-works-better"&gt;Why the CLI Works Better&lt;/h2&gt;
&lt;p&gt;While command line interfaces are often harder to learn than graphical tools, in Git&amp;rsquo;s case I feel that it&amp;rsquo;s the opposite: the CLI helps you learn and focus. Here&amp;rsquo;s why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You don’t need a lot&lt;/strong&gt;: You mainly need to learn five or six simple, core operations which you will use 90% of the time – for everything else you’re generally going to use search engines and forum entries to figure it out case by case, anyway&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It helps you learn&lt;/strong&gt;: Mis-type a command? It will list commands spelled similarly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple add-ins take away the toil&lt;/strong&gt;:  Most of the pains I’ve had with Git have had to do with forgetting my current branch context, or not wanting to type out a whole command – add-ins like &lt;a href="https://github.com/dahlbyk/posh-git"&gt;posh-git&lt;/a&gt; quickly solve these problems and let me have a simple-but-easy experience&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-i-use-graphical-tools"&gt;When I Use Graphical Tools&lt;/h2&gt;
&lt;p&gt;There is still a case when I&amp;rsquo;m happy to depart from the command line: when it comes to merge conflicts, I&amp;rsquo;m all about having a graphic tool to help me sort out the mess. I&amp;rsquo;m a long-time fan of the editor Sublime Text, so I&amp;rsquo;ve recently been happily working with &lt;a href="https://www.sublimemerge.com/"&gt;Sublime Merge&lt;/a&gt; (which allows you to try it out for free).&lt;/p&gt;
&lt;p&gt;But for everything else Git, I love learning with the CLI.&lt;/p&gt;</description></item><item><title>Resolving Merge Conflicts in SQL Source Control: The Basics (Video)</title><link>https://kendralittle.com/2019/12/27/resolving-merge-conflicts-in-sql-source-control-the-basics-video/</link><pubDate>Fri, 27 Dec 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/12/27/resolving-merge-conflicts-in-sql-source-control-the-basics-video/</guid><description>&lt;p&gt;In this 35 minute livestream recording, I commit conflicting code to a Git repo in Azure DevOps Services using Redgate&amp;rsquo;s SQL Source Control, then step through options to fix the conflict.&lt;/p&gt;
&lt;p&gt;We first run through an example where we hit a conflict when pushing to the master branch and resolve that. Then we run through an example where we are using a feature branch and identify the conflict when doing a pull request to merge the change into master.&lt;/p&gt;
&lt;h2 id="resources-to-follow-along"&gt;Resources to Follow Along&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SQL Source Control is part of Redgate&amp;rsquo;s &lt;a href="https://www.red-gate.com/products/sql-development/sql-toolbelt/"&gt;SQL Toolbelt&lt;/a&gt;. It is not free, but we have a free trial. If you don&amp;rsquo;t need automated build and deployments, you can also &lt;a href="https://www.red-gate.com/products/sql-development/sql-source-control/"&gt;purchase SQL Source Control individually&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The Northwind database is &lt;a href="https://github.com/microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs"&gt;shared by Microsoft under the MIT License on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I use the Sublime Merge editor in this demo to resolve the conflict. You can try that out for free at &lt;a href="https://www.sublimemerge.com/"&gt;https://www.sublimemerge.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Lav4WfxUK_A?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Why You Should Take the 2020 State of Database DevOps Survey Today (Video)</title><link>https://kendralittle.com/2019/12/19/why-you-should-take-the-2020-state-of-database-devops-survey-today-video/</link><pubDate>Thu, 19 Dec 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/12/19/why-you-should-take-the-2020-state-of-database-devops-survey-today-video/</guid><description>&lt;p&gt;In this six minute video, I explain why you should take the 2020 State of Database DevOps Survey. The survey is open for a few more days &amp;ndash; we&amp;rsquo;ve had a record number of responses, but we want YOUR input as well!&lt;/p&gt;
&lt;h2 id="take-the-survey"&gt;Take the Survey&lt;/h2&gt;
&lt;p&gt;Take the survey at &lt;a href="Redgate.com/DevOpsSurvey"&gt;Redgate.com/DevOpsSurvey&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/MmCKbKxvhyM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Database Reliability Engineering (22 Minute Video)</title><link>https://kendralittle.com/2019/12/18/database-reliability-engineering-22-minute-video/</link><pubDate>Wed, 18 Dec 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/12/18/database-reliability-engineering-22-minute-video/</guid><description>&lt;p&gt;I was fascinated yesterday to come across the term, &amp;ldquo;Database Reliability Engineering,&amp;rdquo; which I hadn&amp;rsquo;t seen before.&lt;/p&gt;
&lt;p&gt;In this 22 minute whiteboarding session, I talk about why we need new terms for &amp;ldquo;Database Administration,&amp;rdquo; and my initial understanding of what Database Reliability Engineering means by comparison.&lt;/p&gt;
&lt;h2 id="video"&gt;Video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/xNAB_TGCpws?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Online, Resumable, and WAIT_AT_LOW_PRIORITY Operations in SQL Server</title><link>https://kendralittle.com/2019/12/10/online-resumable-and-wait_at_low_priority-operations-in-sql-server/</link><pubDate>Tue, 10 Dec 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/12/10/online-resumable-and-wait_at_low_priority-operations-in-sql-server/</guid><description>&lt;p&gt;&lt;code&gt;ONLINE&lt;/code&gt; operations in SQL Server were simple to understand for years &amp;ndash; we got &lt;code&gt;ONLINE&lt;/code&gt; index rebuilds in SQL Server 2005. That was it for a while.&lt;/p&gt;
&lt;p&gt;Then, things got more complicated: we got more types of indexes. We got &lt;code&gt;ONLINE&lt;/code&gt; options for schema changes that don&amp;rsquo;t involve indexes. We got more options for managing things like blocking, because online operations are really only &lt;em&gt;mostly&lt;/em&gt; online: generally there&amp;rsquo;s going to be at least a short period where an exclusive lock is needed to update metadata. We now have some &lt;code&gt;RESUMABLE&lt;/code&gt; operations coming in, too, for those big operations that are tough to handle.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-05-12-2019_20-33-17.jpg"
alt="An abstract design of waves of various colors" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Along the way, I fell behind. Because these features have steadily come out over a period of time, my brain simply didn&amp;rsquo;t register them all, or possibly I missed seeing them amid other announcements.&lt;/p&gt;
&lt;p&gt;Having realized this, I did a little inventory: here&amp;rsquo;s my rundown of what I understand to be the current state of &lt;code&gt;ONLINE&lt;/code&gt; options. Please feel free to add notes in the comments if I&amp;rsquo;ve missed things, and I&amp;rsquo;ll update the post accordingly. And I admit, in researching this post, I didn&amp;rsquo;t spend time looking at In-Memory OLTP tables &amp;hellip; they come up so rarely that I didn&amp;rsquo;t go there.&lt;/p&gt;
&lt;h2 id="alter-table-alter-column-online-disk-based-rowstore"&gt;ALTER TABLE ALTER COLUMN ONLINE (Disk-Based Rowstore)&lt;/h2&gt;
&lt;p&gt;Usage: most often changing nullability or data type. This is slow against large tables, because we&amp;rsquo;ve got to go rewrite all those rows and hold locks while we do it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ONLINE&lt;/code&gt; options in Azure SQL DB, SQL Server 2016 +&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-table-transact-sql"&gt;Documentation&lt;/a&gt; lists the limitations and impacts. Search for &amp;ldquo;as applies to altering a column&amp;rdquo; to find it in the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: There are no &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; or &lt;code&gt;RESUMABLE&lt;/code&gt; options for &lt;code&gt;ALTER COLUMN ONLINE&lt;/code&gt;.
&lt;/div&gt;
&lt;h2 id="alter-table-add-column-disk-based-rowstore"&gt;ALTER TABLE ADD COLUMN (Disk-Based Rowstore)&lt;/h2&gt;
&lt;p&gt;Usage: commonly done operation in routine software development when adding a new feature. This can be extremely slow when adding a non-nullable column with a default value, read about that in the link below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is an Enterprise Edition feature for adding a non-nullable column with a default value in SQL Server 2012+&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rusanu.com/2011/07/13/online-non-null-with-values-column-add-in-sql-server-11/"&gt;Read about it from Remus Rusanu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: This does not require or allow the use of &lt;code&gt;ONLINE&lt;/code&gt; in the syntax. This is particularly tricky because it occurs in Developer Edition and doesn't occur in Standard Edition. 🤕
&lt;/div&gt;
&lt;p&gt;By the way, if you want to nerd out on what happens behind the scenes when you add or modify various types of columns, Remus has &lt;a href="http://rusanu.com/2011/10/20/sql-server-table-columns-under-the-hood/"&gt;another excellent post on that topic&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="create-index-online-disk-based-rowstore"&gt;CREATE INDEX ONLINE (Disk-Based Rowstore)&lt;/h2&gt;
&lt;p&gt;Usage: index creation is a common operation for both new features and performance tuning.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ONLINE&lt;/code&gt; options in Azure SQL DB, SQL Server 2005+ (Enterprise Edition required)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/create-index-transact-sql#online-option"&gt;Documentation&lt;/a&gt; lists the limitations&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RESUMABLE&lt;/code&gt; added in SQL Server 2019&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: There is no &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; option for &lt;code&gt;CREATE INDEX&lt;/code&gt;.
&lt;/div&gt;
&lt;h2 id="drop-index-online-disk-based-rowstore-clustered-indexes-only"&gt;DROP INDEX ONLINE (Disk-Based Rowstore, Clustered Indexes Only)&lt;/h2&gt;
&lt;p&gt;Usage: I am very hesitant to recommend this. I am mentioning it here to explain why it is probably not your friend and your attempt to do something &lt;code&gt;ONLINE&lt;/code&gt; could end up in a world of regret with a full transaction log.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ONLINE&lt;/code&gt; options in Azure SQL DB, SQL Server 2008+&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From the &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-index-transact-sql"&gt;documentation:&lt;/a&gt; &amp;ldquo;When a clustered index is dropped &lt;code&gt;OFFLINE&lt;/code&gt;, only the upper levels of clustered indexes are removed; therefore, the operation is quite fast. When a clustered index is dropped &lt;code&gt;ONLINE&lt;/code&gt;, SQL Server rebuilds the heap two times, once for step 1 and once for step 2.&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But wait, there&amp;rsquo;s more you should know: because nonclustered rowstore indexes use the clustering key as part of their own definition, this also causes rebuilds of all nonclustered indexes on the table – this can accidentally use a TON of space.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you need to drop a clustered index, generally this pattern is the best bet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Drop or disable all nonclustered indexes (monitor for blocking, but a fast operation otherwise )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drop the clustered &lt;code&gt;OFFLINE&lt;/code&gt; (monitor for blocking, but a fast operation otherwise)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create new clustered if desired (potentially with &lt;code&gt;ONLINE&lt;/code&gt; option)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create or rebuild all nonclustered indexes (potentially with &lt;code&gt;ONLINE&lt;/code&gt; option)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you find a situation where you want to use this, I recommend testing very carefully with a production-like data set before unleashing it on your database.&lt;/p&gt;
&lt;h2 id="alter-table-drop-constraint-online-disk-based-rowstore"&gt;ALTER TABLE DROP CONSTRAINT ONLINE (Disk-based rowstore)&lt;/h2&gt;
&lt;p&gt;Similar to the DROP INDEX for clustered indexes, this works with indexes created by constraints. Since Clustered Primary Keys are implemented with constraints, this basically allows you to do the clustered index drop mentioned above for a clustered PK.&lt;/p&gt;
&lt;h2 id="create-columnstore-index-online"&gt;CREATE COLUMNSTORE INDEX ONLINE&lt;/h2&gt;
&lt;p&gt;Usage: columnstore index creation is increasingly common, as mixed workloads / reporting off of transactional databases is in high demand and far more viable from a software and hardware standpoint than it used to be.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ONLINE&lt;/code&gt; option for Nonclustered Columnstore in Azure SQL Db, SQL Server 2017+&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ONLINE&lt;/code&gt; option for Clustered Columnstore in Azure SQL Db, SQL Server 2019+&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/create-columnstore-index-transact-sql#arguments"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: There are no &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; or &lt;code&gt;RESUMABLE&lt;/code&gt; options for &lt;code&gt;CREATE COLUMNSTORE INDEX&lt;/code&gt;.
&lt;/div&gt;
&lt;h2 id="alter-index-online-disk-based-rowstore"&gt;ALTER INDEX ONLINE (Disk-Based Rowstore)&lt;/h2&gt;
&lt;p&gt;Usage: commonly used to defragment indexes during maintenance operations, sometimes used to adjust fill factor and other index settings&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ONLINE&lt;/code&gt; options for rowstore in Azure SQL DB, SQL Server 2005+&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-index-transact-sql#online-index-operations"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ALTER index is used for maintenance and for things like changing properties such as data compression, fill factor, and index padding&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; in SQL Server 2014+ (using it requires &lt;code&gt;ONLINE=ON&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RESUMABLE = ON&lt;/code&gt; in SQL Server 2017&lt;/li&gt;
&lt;li&gt;Single-partition &lt;code&gt;ONLINE&lt;/code&gt; rebuild in SQL Server 2014+ (prior to that online rebuilds for partitioned indexes is only available for all partitions)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: Enterprise Edition required for &lt;code&gt;ONLINE&lt;/code&gt; rebuilds. &lt;code&gt;REORGANIZE&lt;/code&gt; is an online operation and doesn't require Enterprise Edition, or the &lt;code&gt;ONLINE&lt;/code&gt; keyword, however.
&lt;/div&gt;
&lt;h2 id="alter-index-columnstore-indexes-online-by-another-name"&gt;ALTER INDEX (Columnstore Indexes): Online By Another Name&lt;/h2&gt;
&lt;p&gt;Usage: maintenance operations (some details in the text below)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-index-transact-sql#examples-columnstore-indexes"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Starting with SQL Server 2016 (13.x), rebuilding a columnstore index is no longer necessary in most situations since &lt;code&gt;REORGANIZE&lt;/code&gt; physically removes deleted rows and merges rowgroups. The &lt;code&gt;COMPRESS_ALL_ROW_GROUPS&lt;/code&gt; option forces all OPEN or CLOSED delta rowgroups into the columnstore which previously could only be done with a rebuild. &lt;code&gt;REORGANIZE&lt;/code&gt; is online and occurs in the background so queries can continue as the operation happens.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, for most purposes for columnstore in 2016+, use &lt;code&gt;REORGANIZE&lt;/code&gt; when you want &lt;code&gt;REBUILD ONLINE&lt;/code&gt; 🙃&lt;/p&gt;
&lt;h2 id="alter-table-switch-partition-online-esque"&gt;ALTER TABLE SWITCH PARTITION: Online Esque&lt;/h2&gt;
&lt;p&gt;Usage: loading new data or removing data in &amp;ldquo;sliding window&amp;rdquo; scenarios&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; in Azure SQL DB, SQL Server 2014+&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-table-transact-sql#arguments"&gt;Documentation&lt;/a&gt; (search for &amp;ldquo;switch&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: This technically doesn't have the &lt;code&gt;ONLINE&lt;/code&gt; keyword, but the &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; option makes it online-ish (or at least less offline, if that's a thing).
&lt;/div&gt;</description></item><item><title>What Exactly Would You Say You Do Around Here?</title><link>https://kendralittle.com/2019/12/09/what-exactly-would-you-say-you-do-around-here/</link><pubDate>Mon, 09 Dec 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/12/09/what-exactly-would-you-say-you-do-around-here/</guid><description>&lt;p&gt;The other day, I was looking back at an excellent blog post my colleague Jamie Wallis wrote about what &lt;a href="https://www.red-gate.com/blog/working/why-redgate-has-product-marketing-managers-and-product-managers"&gt;Product Marketing Managers do at Redgate&lt;/a&gt;. I really like the chart he created which explains how Product Marketing Managers work with Product Managers &amp;ndash; what each role focuses on, and where they collaborate.&lt;/p&gt;
&lt;p&gt;I realized that my own role as an Advocate can also be hard to understand.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-22-11-2019_21-16-14.jpg"
alt="Photo of a coffee mug" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I did a podcast &lt;a href="https://kendralittle.com/2019/01/29/what-a-software-evangelist-does-and-where-the-job-is-going-dear-sql-dba-episode-67/"&gt;episode a while back on the topic&lt;/a&gt; &amp;ndash; at the time, my role was called &amp;ldquo;Evangelism&amp;rdquo; rather than &amp;ldquo;Advocacy&amp;rdquo; &amp;ndash; but I don&amp;rsquo;t expect my colleagues to listen to a podcast to figure out what value I can provide.&lt;/p&gt;
&lt;h2 id="why-does-it-matter-if-people-know-what-you-do"&gt;Why Does It Matter If People Know What You Do?&lt;/h2&gt;
&lt;p&gt;I work in a very collaborative role, but I&amp;rsquo;m not special: all roles which work with databases are increasingly collaborative. Even if you act more as a service provider than a partner for a group, it is very beneficial for &lt;em&gt;you&lt;/em&gt; to help important groups in your business understand the value you provide to the organization. Taking the time to do this helps build your relationships with others:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They have a way to understand your team&amp;rsquo;s mission and strategy (rather than guessing based on assumptions or scattered interactions)&lt;/li&gt;
&lt;li&gt;They can see how to best make use of your time&lt;/li&gt;
&lt;li&gt;They have a better understanding of the value you provide to the larger organization &amp;ndash; and that will benefit you whenever they talk about your group to others in the company. They will automatically help you connect with others and provide more value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s another hidden benefit of writing this out. It may remind you that your job is a little bit cooler and more important than you realize, by helping you see the big picture.&lt;/p&gt;
&lt;h2 id="heres-an-example-for-my-role-at-redgate"&gt;Here&amp;rsquo;s an Example for My Role at Redgate&lt;/h2&gt;
&lt;p&gt;I asked Jamie if I could borrow and the diagram which he used in his post. He was happy for me to use it. One of the key partnerships that I have at work is with Redgate&amp;rsquo;s sales team, so I thought specifically of how I work with them when creating this first draft at outlining what I do, and how I can help them.&lt;/p&gt;
&lt;p&gt;In this case, the sales team is my audience for explaining how I work, so I didn&amp;rsquo;t need to outline what &lt;em&gt;they&lt;/em&gt; do as much as I needed to outline what &lt;em&gt;I&lt;/em&gt; do on my own, and in collaboration with their group.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/advocacy-role.png"
alt="Diagram showing the Advocate role and how it works with the sales team"&gt;
&lt;/figure&gt;
&lt;h2 id="ok-i-made-it-how-do-i-share-it"&gt;OK, I Made It, How Do I Share It?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a few way to share things like this which can help:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you work in a physical office, print it and post it!&lt;/li&gt;
&lt;li&gt;Share with new colleagues when they join your organization to help them get oriented&lt;/li&gt;
&lt;li&gt;Add to slide decks in regular meetings to help introduce your team (even if you don&amp;rsquo;t spend time on the slide life, it can be a useful reference in shared PDFs)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="by-the-way-im-not-a-team-lead"&gt;By the Way, I&amp;rsquo;m Not a Team Lead&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not &amp;ldquo;in charge&amp;rdquo; of much of anything but myself these days &amp;ndash; and I&amp;rsquo;m totally OK with that. (Managing other people is hard work!) I still went to the trouble to make this diagram. I&amp;rsquo;ve shared this with my team for input. I also shared this with my manager and let her know how I&amp;rsquo;d like to use this internally with our sales teams to help them understand our role (especially new folks coming on board, but also people whom I just haven&amp;rsquo;t worked with as much yet).&lt;/p&gt;
&lt;p&gt;Earlier in my career, I tended to see activities like this as something that a team lead or manager would do. I didn&amp;rsquo;t really see it as my business.&lt;/p&gt;
&lt;p&gt;Now, I have changed, and the world has changed a bit, too. It&amp;rsquo;s really everyone&amp;rsquo;s business to identify opportunities like this to represent your work a little better. Whenever you find a chance to do something to help connect to your colleagues and customers more clearly, it&amp;rsquo;s worth mapping out a little time to take care of that task yourself!&lt;/p&gt;</description></item><item><title>Installing Redgate SQL Toolbelt with Chocolatey (Video with Transcript)</title><link>https://kendralittle.com/2019/12/02/installing-redgate-sql-toolbelt-with-chocolatey/</link><pubDate>Mon, 02 Dec 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/12/02/installing-redgate-sql-toolbelt-with-chocolatey/</guid><description>&lt;p&gt;Chocolatey is a package manager that helps you install, upgrade, and uninstall packages (applications) on Windows quickly and easily from the command line.&lt;/p&gt;
&lt;p&gt;Spoilers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The command I show in the video is simply: &lt;code&gt;choco install sqltoolbelt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Fun fact, you can also upgrade: &lt;code&gt;choco upgrade sqltoolbelt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;And uninstall: &lt;code&gt;choco uninstall sqltoolbelt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rest of the 6.5 minutes is about related tools you may want to install, and why this is all needed.&lt;/p&gt;
&lt;h2 id="links-from-the-video-check-these-out-while-you-watch"&gt;Links from the Video: Check These Out While You Watch&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://chocolatey.org/products#foss"&gt;https://chocolatey.org/products#foss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chocolatey.org/packages/SqlToolbelt"&gt;https://chocolatey.org/packages/SqlToolbelt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Gists with sample commands for useful installs for Microsoft Data Platform database folks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/SQLvariant/d29ffd1e9905992318b4585c83399328"&gt;Aaron Nelson&amp;rsquo;s List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/LitKnd/93d02119cb10cef6992fd1bcddbdc73a"&gt;Kendra&amp;rsquo;s List&lt;/a&gt; (forked from Aaron&amp;rsquo;s to track my own preferences)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/SQLDBAWithABeard/8aaf68a5a2ee7ce2bd900b66c8834a25"&gt;Rob Sewell&amp;rsquo;s List&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="video-explaining-chocolatey-and-showing-how-to-install-sql-toolbelt-65-minutes"&gt;Video Explaining Chocolatey and Showing How to Install SQL Toolbelt (6.5 Minutes)&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WUNoUUfYEQ8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript"&gt;Transcript&lt;/h2&gt;
&lt;p&gt;Hello and welcome to this live stream episode.&lt;/p&gt;
&lt;p&gt;My name is Kendra Little and I am a DevOps Advocate at Redgate.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;m going to show you something that is a little bit life-changing for me. I have been setting up a new desktop and I&amp;rsquo;ve got a lot of apps to install, including things like Redgate SQL Toolbelt.&lt;/p&gt;
&lt;p&gt;I remembered that I heard recently from my school my teammate Grant Fritchey, who&amp;rsquo;d heard from Steve Jones (also on our team) that when you&amp;rsquo;re setting up Windows the Chocolatey package manager can save you a bunch of time. I&amp;rsquo;d used Chocolatey briefly for setting up some tooling given out by our dev team for some cool preview stuff we&amp;rsquo;re doing, but I hadn&amp;rsquo;t really thought about the fact that it could save me a ton of time setting up Windows desktop apps. And it totally can.&lt;/p&gt;
&lt;p&gt;So I want to show you a little bit about using Chocolatey to set up SQL Toolbelt.&lt;/p&gt;
&lt;p&gt;So far today I have&amp;ndash; just using the command line&amp;ndash; installed SQL Server Management Studio, Azure Data Studio, Azure Data Studio PowerShell. All of the stuff you see on here, I have just installed using the command line.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve even be able been able to customize installation. For example, I like to put the Sysinternals tools &amp;ndash; these are tools like ZoomIt, Process Explorer, and Process Manager from the Sysinternals team at Microsoft&amp;mdash; I like to put these in a custom folder. It&amp;rsquo;s where I always put it. I can actually pass in a parameter for that!&lt;/p&gt;
&lt;h3 id="sample-commands-for-chocolatey-installs-for-sql-server-dbas-some-lists"&gt;Sample Commands for Chocolatey Installs for SQL Server DBAs: Some Lists!&lt;/h3&gt;
&lt;p&gt;So these are a lot of the commands that I like to use: &lt;a href="https://gist.github.com/LitKnd/93d02119cb10cef6992fd1bcddbdc73a"&gt;https://gist.github.com/LitKnd/93d02119cb10cef6992fd1bcddbdc73a&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I forked this off &lt;a href="https://gist.github.com/SQLvariant/d29ffd1e9905992318b4585c83399328"&gt;a really useful gist from Aaron Nelson&lt;/a&gt; who has his favorite things to install with Chocolatey, too.&lt;/p&gt;
&lt;p&gt;You can check out the things that Aaron likes to install, you can check out the things that I like to install.&lt;/p&gt;
&lt;p&gt;All I did was I create a fork from Aaron so I could customize mine.&lt;/p&gt;
&lt;h2 id="how-to-install-redgate-sql-toolbelt-with-chocolatey"&gt;How to Install Redgate SQL Toolbelt with Chocolatey&lt;/h2&gt;
&lt;p&gt;I just uninstalled SQL Toolbelt (before we started). Chocolatey is a package manager and it&amp;rsquo;ll help you both install packages and uninstall them.&lt;/p&gt;
&lt;p&gt;Now I&amp;rsquo;m going to change my command to: &lt;code&gt;choco install sqltoolbelt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This saves you so much time installing packages&amp;ndash; because look it&amp;rsquo;s going out, it&amp;rsquo;s finding the latest version of the Installer, grabbing it for you, and then starting to run it for you.&lt;/p&gt;
&lt;p&gt;Part of the magic here is that you have your list that you can maintain in something like a gist or source control, so you don&amp;rsquo;t even have to remember what all of the things are that you want to install every time. Then you can simply paste them in.&lt;/p&gt;
&lt;p&gt;Then also you don&amp;rsquo;t have to step through all of the wizards. You don&amp;rsquo;t have to download them to directory, click Next Next Next Next finish. You will notice that for some things, like SQL Toolbelt it will pop up a window (an unattended install window) for you&amp;mdash; it&amp;rsquo;ll let you know how it&amp;rsquo;s going. It really depends on how the Installer is written as to how that happens.&lt;/p&gt;
&lt;p&gt;Certain things may take a little bit of time&amp;ndash; like everything else it can take some time&amp;ndash; but this really takes all the work out of it. You can just get it going, start working through your email for the day, or maybe figure out how you&amp;rsquo;re going to configure your livestream on your new computer and just have everything set up unattended in the background.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m really excited for this brave new world. I never thought I would see the day where with Windows it was this easy. We can see over here that SQL Toolbelt has been installed successfully. Freya and I can now move on and get going with our day.&lt;/p&gt;</description></item><item><title>My Git CLI Cheat Sheet</title><link>https://kendralittle.com/2019/11/27/my-git-cli-cheat-sheet/</link><pubDate>Wed, 27 Nov 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/11/27/my-git-cli-cheat-sheet/</guid><description>&lt;p&gt;I created a cheat sheet for the Git Command Line Interface to go along with my &lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o"&gt;Git tutorial for SQL Change Automation video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I find the Git CLI to be very friendly and easier to learn than a GUI interface.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-27-11-2019_19-54-53.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;Download git CLI: &lt;a href="https://git-scm.com/downloads"&gt;https://git-scm.com/downloads&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone &amp;lt;url&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Clone a remote repo (maybe an empty one) into your local directory. &lt;a href="https://git-scm.com/docs/git-clone"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git init&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If not cloning, you might initialize a fresh repo locally. &lt;a href="https://git-scm.com/docs/git-init"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.gitignore file&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I often show people how to use Git with Redgate&amp;rsquo;s SQL Change Automation. For that tool, you can download and unzip the .gitignore file to the folder where your .sqlproj file lives: &lt;a href="https://documentation.red-gate.com/display/sca4/Version+control"&gt;https://documentation.red-gate.com/display/sca4/Version+control&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Another great resource for figuring out what to ignore is &lt;a href="http://gitignore.io/"&gt;http://gitignore.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="essentials"&gt;Essentials&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git status&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Lists modified or added files, with status as to whether they are staged. &lt;a href="https://git-scm.com/docs/git-status"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Stages all modified or added files. You must stage before you commit. &lt;a href="https://git-scm.com/docs/git-add"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to unstage everything: &lt;code&gt;git reset&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-reset"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git commit -m “this is my meaningful message”&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Commits staged files. &lt;a href="https://git-scm.com/docs/git-commit"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git push&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Pushes staged files to remote repo. If upstream branch doesn’t exist, git CLI prints syntax to push to upstream branch with same name as your local branch: simply copy and paste! &lt;a href="https://git-scm.com/docs/git-push"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git pull&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Fetches from remote and updates current branch. If using feature branches, remember to checkout master and pull after you merge a Pull Request on the upstream repo. &lt;a href="https://git-scm.com/docs/git-pull"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="branching"&gt;Branching&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git checkout -b features/mynewfeaturename&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Switches to a newly created branch (the -b tells it to create a new branch. In Azure DevOps (and some other systems), the &amp;ldquo;/&amp;rdquo; means that this branch will be logically grouped into a features &amp;ldquo;folder-like-thing&amp;rdquo; and the branch will be named mynewfeaturename. &lt;a href="https://git-scm.com/docs/git-checkout"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git merge master&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Merges the contents of another branch (in this case, it’s master)into your current branch. &lt;a href="https://git-scm.com/docs/git-merge"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git checkout master&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Switches to existing branch named master (trunk). &lt;a href="https://git-scm.com/docs/git-checkout"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git branch&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Lists all local branches. &lt;a href="https://git-scm.com/docs/git-branch"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git branch -d features/mynewfeaturename&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Deletes local branch features/mynewfeaturename. Only works if you are not in that branch. &lt;a href="https://git-scm.com/docs/git-branch"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="stashing"&gt;Stashing&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git stash -u&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Put away / temporarily removes all modified files. The -u means it applies also to even recently added untracked files (not yet staged). &lt;a href="https://git-scm.com/docs/git-stash"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git stash pop&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Unpack your stash. Doesn’t matter if you’re in a different branch from where you stashed. &lt;a href="https://git-scm.com/docs/git-stash"&gt;Ref&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Upcoming Free Webinars on Database Development and Operations</title><link>https://kendralittle.com/2019/11/19/upcoming-free-webinars-on-database-development-and-operations/</link><pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/11/19/upcoming-free-webinars-on-database-development-and-operations/</guid><description>&lt;p&gt;Fall is in swing, and it&amp;rsquo;s officially webinar season! Here&amp;rsquo;s a bunch of free events I&amp;rsquo;ve got on my calendar.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/New-Sessions.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="weekly-database-devops-live-chats-a-new-experiment-on-youtube"&gt;Weekly Database DevOps Live Chats: A New Experiment on YouTube&lt;/h2&gt;
&lt;p&gt;Stop by to chat! In this session I&amp;rsquo;ll be talking about what I&amp;rsquo;ve learned lately, what&amp;rsquo;s new in Redgate products, and whatever comes up with those who stop by live.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Weds, Nov 20th - 9:30 am Pacific - &lt;a href="https://www.youtube.com/watch?v=u9JGebXmMLg&amp;amp;feature=youtu.be"&gt;YouTube Link&lt;/a&gt; (30 minutes)&lt;/li&gt;
&lt;li&gt;Weds, Nov 27th - 9:30 am Pacific - &lt;a href="https://youtu.be/GOETgLWj4_s"&gt;YouTube Link&lt;/a&gt; (30 minutes)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-make-your-2020-monitoring-strategy-a-success"&gt;How to Make Your 2020 Monitoring Strategy a Success&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Tomorrow, tomorrow, tomorrow!&lt;/em&gt; I&amp;rsquo;ll be chatting with BMW&amp;rsquo;s Tony Maddonna about monitoring in the real world. (The invite says my name is Arneh Eskandari, but I&amp;rsquo;ll be subbing in for Arneh as he&amp;rsquo;s been called away to Jury Duty.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wed, Nov 20th - 8 AM Pacific / 11 AM Eastern - &lt;a href="https://event.on24.com/wcc/r/2112077/9D9D5298046424391E16FC3DFCDD0A81"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="essential-practices-for-high-performing-database-devops-teams"&gt;Essential Practices for High Performing Database DevOps Teams&lt;/h2&gt;
&lt;p&gt;Learn the four essential practices and see demos of these practices in action in this free session.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tue, Nov 26th - 8 AM Pacific / 11 AM Eastern - &lt;a href="https://event.on24.com/wcc/r/2129739/CF500D6FFF741DFD63D5A6A94D88AFF0"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-the-database-is-at-the-heart-of-devops-success"&gt;Why the Database Is at the Heart of DevOps Success&lt;/h2&gt;
&lt;p&gt;Join me and William Durkin from &lt;a href="https://datamasterminds.io/"&gt;Data Masterminds&lt;/a&gt; for insights about how to succeed at database DevOps.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fri, Nov 29 - 6:00 AM Pacific / 9:00 AM Eastern / 3PM CET - ScaleUp 360 online conference - &lt;a href="https://www.scale-up-360.com/en/better-software/agenda/"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="managing-and-automating-test-datasets-for-devops"&gt;Managing and Automating Test Datasets for DevOps&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll be talking about data with Jeffrey Palermo of Clearmeasure. Join us!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Weds, Dec 4 - 7:30 AM Pacific / 10:30 AM Eastern - &lt;a href="https://clearmeasure.zoom.us/webinar/register/1215738468266/WN_bGDsbUfXSwqmfocJIF2LdA"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Links and Resources from How to Architect Successful Database Changes</title><link>https://kendralittle.com/2019/11/06/links-and-resources-from-how-to-architect-successful-database-changes/</link><pubDate>Wed, 06 Nov 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/11/06/links-and-resources-from-how-to-architect-successful-database-changes/</guid><description>&lt;p&gt;Steve Jones and I had a great time today talking about source control for databases and release patterns for performance and availability in Seattle. We had a group of folks who asked terrific questions, made thoughtful comments, and interacted throughout the day.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/exercises-beginning.png"
alt="Group exercises beginning around the room during the workshop"&gt;
&lt;/figure&gt;
&lt;p&gt;Here are some links and resources from the day&amp;hellip;&lt;/p&gt;
&lt;h2 id="suggestion-for-configuration-option-to-make-sql-server-developer-edition-act-like-standard-edition"&gt;Suggestion for Configuration Option to Make SQL Server Developer Edition Act Like Standard Edition&lt;/h2&gt;
&lt;p&gt;This has been requested by the community for many years, but &lt;a href="https://feedback.azure.com/forums/908035-sql-server/suggestions/38934133-trace-flag-sp-configure-option-to-allow-developer"&gt;now is the right time to please vote up this suggestion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After all, Microsoft &lt;a href="https://techcommunity.microsoft.com/t5/SQL-Server/SQL-Server-2019-Standard-Edition/ba-p/986121"&gt;just made Transparent Data Encryption as well as a&lt;/a&gt; &lt;em&gt;&lt;a href="https://techcommunity.microsoft.com/t5/SQL-Server/SQL-Server-2019-Standard-Edition/ba-p/986121"&gt;whole slew of other cool things&lt;/a&gt;&lt;/em&gt; &lt;a href="https://techcommunity.microsoft.com/t5/SQL-Server/SQL-Server-2019-Standard-Edition/ba-p/986121"&gt;available in Standard Edition&lt;/a&gt; in SQL Server 2019. Things have really changed in Microsoft, and your voice matters: voting and commenting helps!&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;INFO&lt;/strong&gt;: &lt;a href="https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2025#new-developer-editions"&gt;Standard Developer Edition&lt;/a&gt; has been added to SQL Server 2025.
&lt;/div&gt;
&lt;h2 id="the-unnecessary-evil-of-the-shared-development-database"&gt;The Unnecessary Evil of the Shared Development Database&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/troyhunt"&gt;Troy Hunt&lt;/a&gt;&amp;rsquo;s amazing post from 2011 is unfortunately still as relevant today as ever. Lots of helpful info on the business value of dedicated development environments is here: &lt;a href="https://www.troyhunt.com/unnecessary-evil-of-shared-development/"&gt;https://www.troyhunt.com/unnecessary-evil-of-shared-development/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="lock-escalation-magic-numbers"&gt;Lock Escalation Magic Numbers&lt;/h2&gt;
&lt;p&gt;5,000 is a magic number&amp;hellip; but it&amp;rsquo;s not necessarily 5,000 rows we are talking about, because &lt;a href="https://kendralittle.com/2017/04/03/which-locks-count-toward-lock-escalation/"&gt;more locks count than you might think&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="how-to-set-up-a-self-hosted-build-agent-for-azure-devops"&gt;How to Set Up a Self-Hosted Build Agent for Azure DevOps&lt;/h2&gt;
&lt;p&gt;This has come up twice in the last two days, so I think a video will be in the works for this! In the meantime:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An overview of Azure Pipelines agents: &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents"&gt;https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you wish to build and / or deploy to a SQL Server on-prem or build with something other than LocalDB, a self-hosted Windows Agent is likely what you want to set up. It works just fine to set that up on your laptop or a VM if you simply need to learn and test and it&amp;rsquo;s fine for it to be offline when your laptop or VM is shut down: &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows"&gt;https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;I haven&amp;rsquo;t tested this &lt;a href="https://docs.microsoft.com/en-us/learn/modules/host-build-agent/"&gt;new Learning Module on the topic, but it looks interesting&lt;/a&gt;. Note: the exercise is specific to using a VM in Azure to host the agent, not on-prem.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-aqua-deployment-model"&gt;The &amp;ldquo;Aqua&amp;rdquo; Deployment Model&lt;/h2&gt;
&lt;p&gt;This series of posts on online deployments from &lt;a href="https://twitter.com/MJSwart"&gt;Michael J Swart&lt;/a&gt; is soooooo good (and the cartoons can&amp;rsquo;t be beat, either): &lt;a href="https://michaeljswart.com/2018/01/100-percent-online-deployments-blue-green-deployment/"&gt;https://michaeljswart.com/2018/01/100-percent-online-deployments-blue-green-deployment/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="my-favorite-whitepaper-and-a-helpful-update-minimal-logging-ftw"&gt;My Favorite Whitepaper and a Helpful Update: Minimal Logging FTW!&lt;/h2&gt;
&lt;p&gt;Not a ton of people in the room knew about the amaaaaazing whitepaper on minimal logging in SQL Server: &lt;a href="https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008/dd425070(v=sql.100)?redirectedfrom=MSDN"&gt;The Data Loading Performance Guide.&lt;/a&gt; This is important when you need to bulk load data fast.&lt;/p&gt;
&lt;p&gt;Some guidance changes for SQL Server 2016+, for info on that, check out this post: &lt;a href="https://blogs.msdn.microsoft.com/sql_server_team/sql-server-2016-minimal-logging-and-impact-of-the-batchsize-in-bulk-load-operations/"&gt;https://blogs.msdn.microsoft.com/sql_server_team/sql-server-2016-minimal-logging-and-impact-of-the-batchsize-in-bulk-load-operations/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="accelerate-state-of-devops-reports-dora--google"&gt;Accelerate State of DevOps Reports (DORA / Google)&lt;/h2&gt;
&lt;p&gt;Only a few folks in the rooms (whom I referred to as my fellow DevOps nerds with the UTMOST respect) knew about these free online reports which represent the findings from more than 30,000 respondents! This is the work led by Dr. Nicole Forsgren, and it is amazing. The DevOps Research and Assessment Group is now part of Google, download their work here: &lt;a href="https://cloud.google.com/devops/"&gt;https://cloud.google.com/devops/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="dbatoolsio"&gt;DBATools.io&lt;/h2&gt;
&lt;p&gt;Some PowerShell steps in our demos featured cmdlets from &lt;a href="https://dbatools.io/"&gt;this wonderful and amazing open source community resource&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="azure-data-studio"&gt;Azure Data Studio&lt;/h2&gt;
&lt;p&gt;Our demo has a narrative outlined in a &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio"&gt;Jupyter notebook from Azure Data Studio&lt;/a&gt;. Please don&amp;rsquo;t blame me for not using a PowerShell notebook, &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/release-notes-azure-data-studio"&gt;those were just released&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="resources-to-download-from-the-day"&gt;Resources to Download from the Day&lt;/h2&gt;
&lt;p&gt;If you are in need of the resources from the day, &lt;a href="https://redgate365-my.sharepoint.com/:u:/g/personal/kendra_little_red-gate_com/EUnB47IXyjVDruy3Cv7ks64BNmREnIVr1GLZQkM-P_Femg?e=ifhb6B"&gt;download them here&lt;/a&gt; (73MB: we use a lot of images and they only compress so much).&lt;/p&gt;
&lt;p&gt;If you weren&amp;rsquo;t at the conference, feel free to download a copy. Please remember, though, that slides contain shorthand to help the speaker deliver a narrative, not full explanations: it&amp;rsquo;s easy to misunderstand based on slides without having been there. In other words, your mileage &lt;em&gt;will&lt;/em&gt; vary, but perhaps you can find inspiration.&lt;/p&gt;
&lt;p&gt;Thanks everyone for attending!&lt;/p&gt;</description></item><item><title>Why I Make Animated Gifs for Presentation Demo Backups</title><link>https://kendralittle.com/2019/10/30/why-i-make-animated-gifs-for-presentation-demo-backups/</link><pubDate>Wed, 30 Oct 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/10/30/why-i-make-animated-gifs-for-presentation-demo-backups/</guid><description>&lt;p&gt;PASS Summit 2019 starts up next Monday with pre-conference sessions. I&amp;rsquo;ve got &lt;a href="https://kendralittle.com/2019/10/24/building-my-schedule-for-pass-summit-2019/"&gt;my schedule all set&lt;/a&gt;, and I&amp;rsquo;m going to be busy: I&amp;rsquo;m speaking in two full-day pre-conference sessions, giving two regular sessions, judging the ever-exciting Speaker Idol competition, and also spending time at the Redgate booth in the expo hall. I scored a little PASS-TV interview to talk about Redgate right before the keynote on the first day.&lt;/p&gt;
&lt;p&gt;I am super lucky to have all these awesome activities lined up, but one thing is clear&amp;hellip;&lt;/p&gt;
&lt;h2 id="i-need-to-be-prepared"&gt;I Need to Be Prepared&lt;/h2&gt;
&lt;p&gt;I will not have a lot of time to react if something goes wrong, such as laptop failure, a critical VM that won&amp;rsquo;t boot up, poor internet connection, etc. When it comes to my talks, I keep copies of my presentations in the cloud and on USB keys in case my laptop fails: that&amp;rsquo;s no big deal, as the conference provides workstations that speakers can use which are loaded with PowerPoint. However, demos are a different story.&lt;/p&gt;
&lt;h2 id="my-old-way-of-managing-this-was-to-create-screenshots-of-my-demos"&gt;My Old Way of Managing This Was to Create Screenshots of My Demos&lt;/h2&gt;
&lt;p&gt;I would then add the screenshots to hidden slides in my presentation. If I couldn&amp;rsquo;t do the demos live or if something weird went wrong, I&amp;rsquo;d un-hide the slides and start showing screenshots of how it was &lt;em&gt;supposed&lt;/em&gt; to work.&lt;/p&gt;
&lt;p&gt;The problem: screenshotting is time-consuming. And doing a run-through where you create screenshots breaks up your flow: the constant pausing, screenshotting, and pasting is very distracting. It&amp;rsquo;s not great demo practice.&lt;/p&gt;
&lt;h2 id="my-new-solution-is-to-record-a-run-through-of-the-demo-then-save-it-as-one-or-more-animated-gifs"&gt;My New Solution Is to Record a Run-Through of the Demo, Then Save It as One or More Animated GIFs&lt;/h2&gt;
&lt;p&gt;This means that I don&amp;rsquo;t need to pause, I can simply rehearse the demo while recording my screen: and I can think about important things, like what are the most useful points to convey about the demo to my specific audience at this event. There is no need to capture sound: if I use the gifs, I&amp;rsquo;ll narrate them live and talk through what is auto-playing on screen. You can even pause a gif that is playing in PowerPoint by clicking the menu at the bottom left of the screen in a live presentation.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/demo-animated-gif-resized.gif"
alt="Mini version of an animated GIF showing a demo that will be presented next week"&gt;
&lt;/figure&gt;
&lt;p&gt;Here is the workflow I use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I use &lt;a href="https://www.techsmith.com/video-editor.html"&gt;Camtasia&lt;/a&gt; to record my screen while I run through the demo. I have been a Camtasia for Mac user for years and find it very easy to use.&lt;/li&gt;
&lt;li&gt;I save the project, make sure I have the resolution set to 1080p and the demo is full-screened, and do any simple edits needed (such as small cuts of where I made a mistake that&amp;rsquo;s not relevant)&lt;/li&gt;
&lt;li&gt;I add a fade transition to the beginning and end of the clip to make it clear where it starts and ends (the animated gif will repeat when open on a slide in PowerPoint)&lt;/li&gt;
&lt;li&gt;I publish the file as a gif (I use frame rate 5) and save it in the file share with my presentation, where it automatically syncs to cloud storage&lt;/li&gt;
&lt;li&gt;I also add the gif file into the presentation itself on a hidden slide&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For pretty short demos (less than a minute) I have even found that it&amp;rsquo;s convenient to show the animated gif and talk through it instead of doing a live demo. This is nice because it reduces switching in and out of PowerPoint when I want to show something quickly: screen switching takes time and can be visually jarring for the audience on many projectors.&lt;/p&gt;
&lt;h2 id="one-downside-of-using-animated-gifs-this-way"&gt;One Downside of Using Animated GIFs This Way&lt;/h2&gt;
&lt;p&gt;Your PowerPoint files can become quite large. This was also a downside of my screenshot approach, so I&amp;rsquo;m already used to large PowerPoints. If it is an issue for you, you could simply not add the animated gifs to the PowerPoint and store them and access them separately if needed.&lt;/p&gt;
&lt;p&gt;All in all, I&amp;rsquo;m quite happy with my updated method of &amp;ldquo;accident proofing&amp;rdquo; my talks. Long live the animated gif!&lt;/p&gt;</description></item><item><title>Thinking About Robert Davis</title><link>https://kendralittle.com/2019/10/25/thinking-about-robert-davis/</link><pubDate>Fri, 25 Oct 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/10/25/thinking-about-robert-davis/</guid><description>&lt;p&gt;It&amp;rsquo;s been more than a year and a half since &lt;a href="https://twitter.com/SQLSoldier"&gt;Robert Davis&lt;/a&gt; passed away. I wrote a bit about Robert&amp;rsquo;s passing &lt;a href="https://kendralittle.com/2018/04/03/remembering-robert-davis-aka-sqlsoldier/"&gt;last April&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t written about him since, but I think about Robert a lot.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-25-10-2019_02-10-47.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="when-i-remember-robert"&gt;When I Remember Robert&lt;/h2&gt;
&lt;p&gt;I think about Robert when I work on a tough problem that he would have found interesting, when chatting about database nerdery on Twitter, when preparing for a conference or training that I know he would have been excited to attend.&lt;/p&gt;
&lt;p&gt;I remember him when I get a great new photo of one of my dogs, because I know he would have loved to see it.&lt;/p&gt;
&lt;p&gt;When I remember Robert now, I remember how delighted he was to solve all sorts of puzzles, and I remember the sound of his laughter. He helps me try to remember to be kind. To be more helpful to others.&lt;/p&gt;
&lt;h2 id="a-simple-remembrance"&gt;A Simple Remembrance&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t have a big takeaway or piece of insight from this post. I simply wanted to write something about our friend who isn&amp;rsquo;t with us anymore, because he continues to make an impact on my world.&lt;/p&gt;
&lt;p&gt;Wish you were still here.&lt;/p&gt;</description></item><item><title>Building My Schedule for PASS Summit 2019</title><link>https://kendralittle.com/2019/10/24/building-my-schedule-for-pass-summit-2019/</link><pubDate>Thu, 24 Oct 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/10/24/building-my-schedule-for-pass-summit-2019/</guid><description>&lt;p&gt;It&amp;rsquo;s just ten days until PASS Summit 2019 begins in Seattle. The &lt;a href="https://www.pass.org/summit/2019/Learn/Schedule.aspx"&gt;schedule is up&lt;/a&gt; and there are loads of good sessions. Here&amp;rsquo;s what I&amp;rsquo;m putting on my calendar to make sure that I don&amp;rsquo;t miss it: along with some sessions I wish I could attend that I&amp;rsquo;ll be sure to catch the videos of afterwards.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-24-10-2019_18-10-32.jpg"
alt="Overhead view of people walking on pavement that is painted to look like a calendar." width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="monday-nov-4-redgate-sql-in-the-city-summit-seattle-pre-con-day---room-3ab"&gt;Monday, Nov 4: &amp;ldquo;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92888"&gt;Redgate SQL in the City Summit Seattle&lt;/a&gt;&amp;rdquo; Pre-Con Day - Room 3AB&lt;/h2&gt;
&lt;p&gt;This is going to be a &lt;em&gt;fantastic&lt;/em&gt; day: loads of DevOps learning and sharing. I&amp;rsquo;ll be talking about implementing and improving Database DevOps with some of my very favorite DevOps and SQL Server specialists: Steve Jones, Grant Fritchey, Ike Ellis, Hamish Watson, and Arneh Eskandari. The great thing about having a list of speakers like this is that you get to hear about varied real-world experiences and different takes on topics, plus there is loads of time to bounce ideas off people. There&amp;rsquo;s still time to sign up and &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92888"&gt;join us&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="tuesday-nov-5-how-to-architect-successful-database-changes-source-control-and-release-patterns-for-performance-and-availability-pre-con-day---room-604"&gt;Tuesday, Nov 5: &amp;ldquo;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92841"&gt;How to Architect Successful Database Changes: Source Control and Release Patterns for Performance and Availability&lt;/a&gt;&amp;rdquo; Pre-Con Day - Room 604&lt;/h2&gt;
&lt;p&gt;On Tuesday, Steve Jones and I will be talking about development patterns that enable you to frequently release database changes while maintaining high production uptime and minimizing the impact of your deployments on your target environment. This isn&amp;rsquo;t the easiest thing to do, but it&amp;rsquo;s increasingly important to understand the methods behind sneaking in database deployments to live systems without causing problems for users: we&amp;rsquo;ll share what we&amp;rsquo;ve learned over the course of our careers, as well as some insights into what we see as the future of database development.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tuesday evening&lt;/strong&gt;: There is a &lt;a href="https://www.eventbrite.com/e/pass-summit-women-in-tech-happy-hour-tickets-78056157067"&gt;Women in Tech Happy Hour from 4-6 PM&lt;/a&gt; at the &lt;a href="https://www.eventbrite.com/e/pass-summit-women-in-tech-happy-hour-tickets-78056157067#map-target"&gt;Tap House Grill&lt;/a&gt;. I&amp;rsquo;ll be late, but it&amp;rsquo;s a great event I&amp;rsquo;d like to make, even if it&amp;rsquo;s just for 15 minutes. Following this, there is a Welcome Reception in the Keynote room back at the Conference Center. I will almost certainly head back to do a little preparation for my presentation the next day and an early night of sleep, however: after speaking a lot during the day I&amp;rsquo;ll be tired and my voice and brain will need a rest. (Note: sometimes people feel bad for taking nights off networking at conferences: fear of missing out can kick in pretty easy. But if you need time to chill and recharge, do it!)&lt;/p&gt;
&lt;h2 id="wednesday-nov-6-day-1-of-the-main-conference"&gt;Wednesday, Nov 6: Day 1 of the main conference&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;08:15 AM - 09:45 AM&lt;/strong&gt;: &lt;a href="https://www.pass.org/summit/2019/Learn/Keynotes.aspx"&gt;Keynote with Rohan Kumar&lt;/a&gt;. I&amp;rsquo;ll watch this remotely on &lt;a href="https://www.pass.org/summit/2019/Home.aspx"&gt;PASS TV&lt;/a&gt;, as I am presenting a session directly afterward. If you can make it in person, everyone will be walking to the big Keynote Room, follow the crowd.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10:15 AM - 11:30 AM&lt;/strong&gt;: I&amp;rsquo;m presenting &amp;ldquo;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98639"&gt;Why the Database is at the Heart of DevOps Success&lt;/a&gt;&amp;rdquo; in room 615 (it was 608, but we had a room change). I love, love, love this session and am so excited to share it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;11:30 AM - 01:30 PM&lt;/strong&gt;: I&amp;rsquo;m going to swing by one of the DevOps tables at the &lt;a href="https://www.pass.org/Portals/0/_Community/PASS%20Summit%202019/PASS_19_BOFLuncheon_Handout_1.pdf?ver=2019-10-21-132934-733"&gt;Birds of a Feather lunch&lt;/a&gt; (Dining Hall, 4EF) for a quick chat, then head to the Redgate booth in the Exhibit Hall (4B).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1:30 PM - 2:45 PM&lt;/strong&gt;: I cannot possibly miss Pam LaHoud on &amp;ldquo;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98848"&gt;Improving Availability in SQL Server and Azure SQL Database with Accelerated Database Recovery and Resumable Operations&lt;/a&gt;.&amp;rdquo; She is magic and these new features are magic, too. Room 6B.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2:50 PM - 3:30 PM&lt;/strong&gt;: Back to the Exhibit Hall (4B): I love hearing questions and chatting DevOps at the Redgate booth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3:15 PM - 4:30 PM&lt;/strong&gt;: The Exhibit Hall closes at 3:30, so I&amp;rsquo;ll probably be late for this. I&amp;rsquo;ll try to find a spare seat in &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=93999"&gt;Linux Fundamentals for SQL Server DBAs&lt;/a&gt; by Hamish Watson in Room 608.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;04:45 PM - 6:00 PM&lt;/strong&gt;: It&amp;rsquo;s &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98948"&gt;SPEAKER IDOL time&lt;/a&gt;! Round 1. This is a really fun series of lightning talks with a fun competition mixed in. I get to be a judge! I can&amp;rsquo;t wait, I learn a ton from Speaker Idol every year. Be there in room 2AB.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6:00 PM - 8:00 PM&lt;/strong&gt;: Have some food and drinks on the Exhibitors: and maybe talk to us as well if you like, we&amp;rsquo;re nice enough - Exhibit Hall, 4B&lt;/p&gt;
&lt;p&gt;If my voice isn&amp;rsquo;t already starting to fail, I&amp;rsquo;ll head to &lt;a href="https://www.eventbrite.com/e/pass-summit-2019-games-night-wednesday-tickets-66695779873"&gt;Game Night at 8PM&lt;/a&gt; (Ballroom 6A).&lt;/p&gt;
&lt;h2 id="thursday-nov-7-day-2-of-the-main-conference"&gt;Thursday, Nov 7: Day 2 of the main conference&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;08:15 AM - 09:45 AM&lt;/strong&gt;: &lt;a href="https://www.pass.org/summit/2019/Learn/Keynotes.aspx"&gt;Keynote with Tarah Wheeler&lt;/a&gt; (Keynote Room). Imma try to attend this one in person. I need to make notes for a post-event webinar that I&amp;rsquo;m doing with Grant, Kathi, and Steve: &amp;ldquo;&lt;a href="https://event.on24.com/wcc/r/2118041/B2CD049ED1ECB55DFFCDA7148ABB3DD1"&gt;What we learned at PASS Summit&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10:15 AM - 11:30 AM&lt;/strong&gt;: &amp;ldquo;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98832"&gt;Enabling End to End Scenarios with Data Virtualization in SQL Server 2019&lt;/a&gt;&amp;rdquo; with James Rowland-Jones, TCC Yakima 1. It&amp;rsquo;s a hike over to the TCC building (you can do it all inside the convention center using a skybridge for convenience), but this is something I must learn more about for cross-platform scenarios. And isn&amp;rsquo;t this a crazy world: James works at Microsoft and he&amp;rsquo;s presenting on how to use ORACLE AND SQL SERVER TOGETHER! Oh brave new world!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;11:30 AM - 01:15 PM&lt;/strong&gt;: &lt;a href="https://www.pass.org/summit/2019/Learn/Keynotes.aspx"&gt;Women in Tech Lunch with LaShana Lewis&lt;/a&gt; (Keynote Room). I can&amp;rsquo;t remember if I signed up for this when I registered, but I&amp;rsquo;ll find out when I check into the conference. If I didn&amp;rsquo;t, I&amp;rsquo;ll attend the &lt;a href="https://www.pass.org/Portals/0/_Community/PASS%20Summit%202019/PASS_19_BOFLuncheon_Handout_1.pdf?ver=2019-10-21-132934-733"&gt;Birds of a Feather lunch&lt;/a&gt; (Dining Hall, 4EF) and catch LaShana&amp;rsquo;s talk via recording afterward. Hopefully will fit in some time at the Redgate Booth in the Exhibit Hall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1:30 PM - 02:45 PM&lt;/strong&gt;: &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98059"&gt;SQL Server in Containers: Your Next Dev/Test/Integration/Upgrade Server&lt;/a&gt;. Grant Fritchey has some amazing things to show and I&amp;rsquo;m going to tweet all about it. Room 618.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2:50 PM - 3:30 PM&lt;/strong&gt;: Back to the Exhibit Hall (4B) to meet up with friends at the Redgate booth. Exhibit hall closes at 3:30 again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3:15 PM - 04:30 PM&lt;/strong&gt;: I&amp;rsquo;d love to see Tobias Ternstrom talk about &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98739"&gt;Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases&lt;/a&gt;. Room 3AB.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4:45 PM - 06:00 PM&lt;/strong&gt;: &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98949"&gt;SPEAKER IDOL - ROUND 2&lt;/a&gt; in Room 2AB. The action heats up in this second round with an all-new set of contestants. A great community session.&lt;/p&gt;
&lt;p&gt;I have an early session Friday, so I&amp;rsquo;ll be heading to dinner with Friends of Redgate and going to bed early. I wish I could go to &lt;a href="https://www.eventbrite.com/e/pass-summit-2019-games-night-wednesday-tickets-66695779873"&gt;Game Night at 8PM&lt;/a&gt; (Ballroom 6A) as well, though.&lt;/p&gt;
&lt;h2 id="friday-nov-8-final-day-of-the-conference"&gt;Friday, Nov 8: Final day of the conference&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;8:00 AM - 09:15 AM&lt;/strong&gt;: I&amp;rsquo;ve gotta see &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92529"&gt;Batch Execution Mode on Rowstore Indexes&lt;/a&gt; by Niko Neugebauer in room 6B. I will have to watch the recording of Niko&amp;rsquo;s excellent talk because &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98949"&gt;SPEAKER IDOL - ROUND 3&lt;/a&gt; is in Room 2AB. Start your day off with a fun sampler of learning in this final heat of the first round.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9:30 AM - 10:45 AM&lt;/strong&gt;: I&amp;rsquo;m presenting &amp;ldquo;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92199"&gt;Best Practices for Branching Database Code in Git&lt;/a&gt;&amp;rdquo; in room 6A. WOO HOO!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10:30 AM - 2:00 PM&lt;/strong&gt;: Exhibit Hall (4B) - I can&amp;rsquo;t show up at 10:30 unless literally no-body is in the audience of my talk, but I&amp;rsquo;ll get there as soon as I can for the last day at the booth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2:00 PM - 03:15 PM&lt;/strong&gt;: &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=98951"&gt;SPEAKER IDOL - FINALE&lt;/a&gt;, Room 2AB. A winner will be crowned! Errr&amp;hellip; actually I don&amp;rsquo;t think there&amp;rsquo;s a crown, but there IS a very cool prize.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3:30 PM - 04:45 PM:&lt;/strong&gt; I wish I could see &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92480"&gt;Continuous Intelligence&amp;hellip; What&amp;rsquo;s This All About?&lt;/a&gt; by Gabi Münster in TCC Skagit 4. Unfortunately I have to jet to the airport to get home to my puppy, who I&amp;rsquo;ll be missing like crazy all week. I know, excuses excuses.&lt;/p&gt;</description></item><item><title>Workshop Report: Overcoming Obstacles on the Journey to Continuous Delivery for Databases (Video with Transcript)</title><link>https://kendralittle.com/2019/10/17/workshop-report-overcoming-obstacles-on-the-journey-to-continuous-delivery-for-databases-video-with-transcript/</link><pubDate>Thu, 17 Oct 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/10/17/workshop-report-overcoming-obstacles-on-the-journey-to-continuous-delivery-for-databases-video-with-transcript/</guid><description>&lt;p&gt;In this video, Freyja the puppy and I talk about a recent workshop which I facilitated at the IDC DevOps conference in London.&lt;/p&gt;
&lt;p&gt;We cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=X7AN8_bZ2Co&amp;amp;t=105s"&gt;01:45&lt;/a&gt; The workshop methodology: about &lt;a href="https://medium.muz.li/a-super-simple-exercise-for-solving-almost-any-product-design-challenge-f9e6c0019d7d"&gt;the Lightning Decision Jam Session, by AJ&amp;amp;Smart / Jonathan Courtney&lt;/a&gt;. I think this is a great format, and you may want to use this yourself for a workshop with your team (on any problem-solving topic)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=X7AN8_bZ2Co&amp;amp;t=333s"&gt;05:33&lt;/a&gt; Key findings from our group about how to overcome the top obstacles to Continuous delivery for databases&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A transcript of the session is below the video.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/X7AN8_bZ2Co?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-edited-a-bit-for-clarity"&gt;Transcript (edited a bit for clarity)&lt;/h2&gt;
&lt;h3 id="hi-im-kendra-little-im-a-devops-advocate-for-redgate"&gt;Hi, I&amp;rsquo;m Kendra Little: I&amp;rsquo;m a DevOps Advocate for Redgate&lt;/h3&gt;
&lt;p&gt;What this means is that I get to spend time talking to folks and thinking about the patterns and practices that help people successfully develop and deploy stable changes to their databases, that bring value to the customers of these organizations.&lt;/p&gt;
&lt;p&gt;Recently I went to a conference that was really great: it was the IDC DevOps conference in London. At this conference, I really liked the format. In the morning we had a series of presentations, and in the afternoon we had workshops where we talked about different problems and potential solutions.&lt;/p&gt;
&lt;h3 id="these-workshops-were-collaborative"&gt;These workshops were collaborative&lt;/h3&gt;
&lt;p&gt;I hosted a workshop, but I didn&amp;rsquo;t get to just get to tell the whole group: here&amp;rsquo;s how it&amp;rsquo;s done. That wasn&amp;rsquo;t the point!&lt;/p&gt;
&lt;p&gt;The problem that we were solving in my group was how to overcome the top obstacles to continuous delivery for databases.&lt;/p&gt;
&lt;p&gt;What we zoomed in on was the fact that when you&amp;rsquo;re starting out on a journey to implement Database DevOps, you&amp;rsquo;re working across silos. You&amp;rsquo;ve got the database folks generally working in their own silo. You&amp;rsquo;ve got developers generally working in another silo, and the larger the organization the more complex it can be to establish new processes between these two groups, because they have different ways of working.&lt;/p&gt;
&lt;p&gt;Starting out at the workshop, a lot of people at the conference were in different phases of implementing DevOps, and many were early on. So we did this exercise that not everybody was bought into at first.&lt;/p&gt;
&lt;p&gt;This exercise is built on a format called the &lt;a href="https://medium.muz.li/a-super-simple-exercise-for-solving-almost-any-product-design-challenge-f9e6c0019d7d"&gt;Lightning Decision Jam Session by AJ&amp;amp;Smart&lt;/a&gt;, and that itself is based on a great book called &lt;a href="https://www.thesprintbook.com/"&gt;Sprint&lt;/a&gt;. It&amp;rsquo;s about design thinking.&lt;/p&gt;
&lt;h3 id="heres-a-little-bit-about-how-the-workshop-goes"&gt;Here&amp;rsquo;s a Little Bit About How the Workshop Goes&lt;/h3&gt;
&lt;p&gt;You have everyone take a stack of either paper or post-it notes: having something sticky works well though. Everybody privately writes down different potential solutions to how could we make it easy to get people to take on the new processes required for database DevOps.&lt;/p&gt;
&lt;h3 id="1-generating-solutions"&gt;1. Generating Solutions&lt;/h3&gt;
&lt;p&gt;Everyone generates these solutions. You focus on quantity, not quality. The idea is that everyone should just start generating ideas, because it&amp;rsquo;s like brainstorming but without the pressure of having other people listen to your ideas. You&amp;rsquo;re just recording them on sticky notes. You have a time limit for that, and we did about ten minutes of people generating their solutions.&lt;/p&gt;
&lt;p&gt;At first some people were like, well, I don&amp;rsquo;t know what solutions I have for this because I haven&amp;rsquo;t done Database DevOps successfully!&lt;/p&gt;
&lt;p&gt;But the truth is most people in the group had gone through IT changes and seen what worked well and what didn&amp;rsquo;t. Most people in the group had observed a lot of behavior among their co-workers and seen what&amp;rsquo;s difficult and what&amp;rsquo;s not difficult to get people to do. And also a lot of people at the table had gone through Agile transformations for their application tier, and had seen what worked and didn&amp;rsquo;t work for that. Everyone already had a lot of reference material to work from.&lt;/p&gt;
&lt;h3 id="2-voting"&gt;2. Voting&lt;/h3&gt;
&lt;p&gt;After you generate all these solutions, you come together. Each solution needs to be legible because you&amp;rsquo;re not gonna defend them, you&amp;rsquo;re not gonna explain them. What happens is the facilitator puts them up on a board: we just used a wall in the room. You spread them out on the wall and you equip everyone with either voting dots or a pen. Everyone reads silently reads all the solutions and puts dots on the one that any of them that they think would be viable.&lt;/p&gt;
&lt;p&gt;Now, you&amp;rsquo;re not limited. You can vote for as many of these as you want, but the point is that you don&amp;rsquo;t vote for your own because you already submitted yours: you already kind of voted for your own. Everybody silently votes on these using dots. The idea is not to do a bunch of talk during this, just read them and vote on them.&lt;/p&gt;
&lt;h3 id="3-filtering"&gt;3. Filtering&lt;/h3&gt;
&lt;p&gt;Then you do a filtering process. We filtered out anything that had less than three dots. These aren&amp;rsquo;t terrible ideas, necessarily, these are just things that the group doesn&amp;rsquo;t think are gonna be the most effective. That narrows down the window of what you have.&lt;/p&gt;
&lt;h3 id="4-effort--impact-scale"&gt;4. Effort / Impact Scale&lt;/h3&gt;
&lt;p&gt;Then you take down the ideas that pass the dot filter, and you arrange them by the amount of impact they have in the amount of difficulty they&amp;rsquo;ll be.&lt;/p&gt;
&lt;p&gt;This is where having an axis drawn on a whiteboard can come in handy. We just had to imagine the axis ourselves, but ideally you&amp;rsquo;ve got a vertical access which is the amount of impact a suggestion will have on the organization / the amount it&amp;rsquo;ll help you solve the problem. The horizontal axis is how difficult it is.&lt;/p&gt;
&lt;p&gt;Things that are very far to the left and very high up will be very high impact and not a lot of work. You can also have things that are high impact and a lot of work (top right quadrant). You can have things that are low impact and a lot of work (lower right quadrant). You have things that are low impact, but they are not a lot of work, either (lower left quardant).&lt;/p&gt;
&lt;p&gt;We arranged all the ideas collaboratively on this scale.&lt;/p&gt;
&lt;p&gt;This led us to identify things that are high impact but not super duper challenging to do.&lt;/p&gt;
&lt;h3 id="the-findings-that-the-group-came-up-with-were"&gt;The Findings That the Group Came Up With Were&lt;/h3&gt;
&lt;h3 id="1-version-control"&gt;1. Version Control&lt;/h3&gt;
&lt;p&gt;For the top three things that help people overcome process obstacles to initiating change for continuous delivery for databases, our group found that establishing version control for database code is number one.&lt;/p&gt;
&lt;p&gt;Version control is the foundation of so much collaboration between people that you really need to get code into version control and focus on that. This isn&amp;rsquo;t always the simplest thing in the world, but it&amp;rsquo;s really a necessarily necessary enabler for everything else.&lt;/p&gt;
&lt;h3 id="2-minimum-viable-dataset"&gt;2. Minimum Viable Dataset&lt;/h3&gt;
&lt;p&gt;The group also had a concept of a Minimum Viable dataset. I loved this point: in order to successfully do development work, we need a copy of a dataset that enables progress.&lt;/p&gt;
&lt;p&gt;In some cases, if production is a 10 terabyte environment our Minimum Viable Dataset for development might be much smaller. This viable data set may need to replace sensitive data that lives in production with non sensitive data. In some environments it may need to be synthesized. But we need to have this to support this work.&lt;/p&gt;
&lt;h3 id="3-constant-communications-between-teams"&gt;3. Constant Communications Between Teams&lt;/h3&gt;
&lt;p&gt;The third thing that the group found is this enabler to break down these silos between teams and get database DevOps going is constant communications between the teams. We need to have teams really working together to establish these new processes, and we need to have the teams listening to one another.&lt;/p&gt;
&lt;h3 id="enabling-all-of-these-an-executive-sponsor"&gt;Enabling All of These: An Executive Sponsor&lt;/h3&gt;
&lt;p&gt;Additionally, in order to enable all of these things to happen, if you can identify an executive sponsor who can meet with the teams on a regular basis and emphasize how this project meets organization goals, it helps these teams to work together.&lt;/p&gt;
&lt;p&gt;For cultural change, it&amp;rsquo;s good for teams to know they are being supported by the organization at large. That is an underpinning that can help this change go through.&lt;/p&gt;
&lt;p&gt;This was a really fun workshop at the IDC DevOps conference. Every time I&amp;rsquo;ve done this exercise, I&amp;rsquo;ve been impressed at the insights that come from the group: which is always so much fun because at the beginning the exercise there&amp;rsquo;s so much doubt as to whether the team knows enough to overcome the challenge! But in this case, we certainly did.&lt;/p&gt;
&lt;p&gt;Thanks for joining me for this talk. I&amp;rsquo;m Kendra Little from Redgate: and this is Freyja, our local expert on Corginetes who has joined me for this quick video. Bye folks, I&amp;rsquo;ll see you again in another video soon.&lt;/p&gt;</description></item><item><title>Setting a Custom Variable in an Azure DevOps Pipeline with PowerShell</title><link>https://kendralittle.com/2019/09/02/setting-a-custom-variable-in-an-azure-devops-pipeline-with-powershell/</link><pubDate>Mon, 02 Sep 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/09/02/setting-a-custom-variable-in-an-azure-devops-pipeline-with-powershell/</guid><description>&lt;p&gt;Recently, I was doing a bit of work in Azure DevOps Services, preparing a demo for an upcoming webinar. I ran into a simple but frustrating problem.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-14-08-2019_21-36-36.jpg"
alt="An ice cream cone that has been dropped on its side." width="230"&gt;
&lt;/figure&gt;
Part of the demo does the following magic, using a branch policy and pull request automation trigger, combined with some of Redgate&amp;rsquo;s extensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Builds/validates database code&lt;/li&gt;
&lt;li&gt;Creates a lightweight clone of the &amp;ldquo;production&amp;rdquo; database (I&amp;rsquo;m using &lt;a href="https://www.brentozar.com/archive/2015/10/how-to-download-the-stack-overflow-database-via-bittorrent/"&gt;a copy of StackOverflow&lt;/a&gt;, thanks Brent &amp;amp; the folks at Stack)&lt;/li&gt;
&lt;li&gt;Creates a release artifact summarizing the changes that&amp;rsquo;ll be deployed to the clone, exports it, then deploys the changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This combination of actions is lovely: reviewers of the pull request have validation that the code builds, they know it deploys successfully, and they can even look at deployment timings. Plus, they have a real environment to review the change.&lt;/p&gt;
&lt;p&gt;I was working on improving something simple about my demo: giving the cloned database a clear, accurate name that ties to the Pull Request Id.&lt;/p&gt;
&lt;p&gt;Previously, I&amp;rsquo;d been using the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/release/variables#default-variables"&gt;default $(Release.ReleaseId)&lt;/a&gt; variable in the database name, but I decided that I would prefer to identify this with the PR number, and for the cloned database to be replaced when re-running the automation for a PR (if code in it changes, etc).&lt;/p&gt;
&lt;h2 id="there-wasnt-a-default-variable-that-does-exactly-what-i-wanted"&gt;There Wasn&amp;rsquo;t a Default Variable That Does Exactly What I Wanted&lt;/h2&gt;
&lt;p&gt;Looking at my options &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/release/variables#default-variables"&gt;in the default variables&lt;/a&gt;, the closest thing to what I was going for is $(Release.{alias}.SourceBranch)&amp;quot;. My alias for my build artifact is _StackOverflow-CI, so I referenced that as $(Release.Artifacts._StackOverflow-CI.SourceBranch).&lt;/p&gt;
&lt;p&gt;That outputs a path like refs/pull/34/merge. For a variety of reasons, I don&amp;rsquo;t want a bunch of forward slashes running around in my database names. But no problem: looking at the documentation, I saw that I can &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables#set-in-script"&gt;set a custom variable easily in a PowerShell task step in my pipeline&lt;/a&gt;. Maybe there&amp;rsquo;s an even simpler way to do this, but that looked like a fast and easy way to replace those slashes with underscores, so I went for it.&lt;/p&gt;
&lt;h2 id="a-key-piece-of-info-new-variables-are-only-available-in-downstream-steps"&gt;A Key Piece of Info: New Variables Are Only Available in Downstream Steps&lt;/h2&gt;
&lt;p&gt;This ended up being a bit time consuming for me, because there&amp;rsquo;s one important piece of the documentation which I didn&amp;rsquo;t notice. I skipped to the sample code and missed this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To set a variable from a script, you use the task.setvariable logging command. This does not update the environment variables, but it does make the new variable available to &lt;em&gt;downstream steps&lt;/em&gt; within the same job.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables#set-in-script"&gt;Azure DevOps Services - Variables doc&lt;/a&gt; - emphasis mine&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Having missed that fact, I struggled with my code for a good while, because I was trying to set the variable and then read it for validation in the same task. That didn&amp;rsquo;t work, so I thought I wasn&amp;rsquo;t actually setting the variable properly. Whoops.&lt;/p&gt;
&lt;h2 id="some-simple-sample-code"&gt;Some Simple Sample Code&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you have a PowerShell script task in your Azure DevOps release pipeline. You set it to &amp;ldquo;inline&amp;rdquo; type, and you have the following code in there:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Artifacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_StackOverflow-CI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SourceBranch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;-replace&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;_&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;No problem reading &lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;##vso[task.setvariable variable=DUCKS]&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Trying to read &lt;/span&gt;&lt;span class="nv"&gt;$env:DUCKS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will produce something like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;2019-08-14T20:56:19.8412596Z refs/pull/34/merge
2019-08-14T20:56:19.8424967Z No problem reading refs_pull_34_merge
2019-08-14T20:56:19.8431236Z ##[debug]Processed: ##vso[task.setvariable variable=DUCKS]refs_pull_34_merge
2019-08-14T20:56:19.8545546Z Trying to read &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Totally looks like our $env.DUCKS variable didn&amp;rsquo;t get set.&lt;/p&gt;
&lt;p&gt;However, if you add an additional PowerShell script task to the same job, also set to &amp;ldquo;inline type&amp;rdquo;, which contains that same final line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Trying to read &lt;/span&gt;&lt;span class="nv"&gt;$env:DUCKS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That will do what you expect and produce:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;2019-08-14T20:56:21.4502122Z Trying to read refs_pull_34_merge&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="i-guess-reading-is-fundamental"&gt;I Guess Reading Is Fundamental&lt;/h2&gt;
&lt;p&gt;This all makes perfect sense to me, now that I think about it.&lt;/p&gt;
&lt;p&gt;In my defense, it&amp;rsquo;s been a loooong time since I&amp;rsquo;ve thought about environment variables in Windows! I couldn&amp;rsquo;t tell you how many times I looked at that doc and missed this important detail: it was more than a few times.&lt;/p&gt;
&lt;p&gt;Hopefully this helps someone else out there who misses the same thing I did.&lt;/p&gt;</description></item><item><title>Git Command Line Tutorial with SQL Change Automation for SSMS (Video)</title><link>https://kendralittle.com/2019/08/26/git-command-line-tutorial-with-sql-change-automation-for-ssms-video/</link><pubDate>Mon, 26 Aug 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/08/26/git-command-line-tutorial-with-sql-change-automation-for-ssms-video/</guid><description>&lt;p&gt;I&amp;rsquo;m excited for Redgate&amp;rsquo;s new &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/entrypage/ssms-addin"&gt;SQL Change Automation plugin for SQL Server Management Studio&lt;/a&gt; (SSMS).&lt;/p&gt;
&lt;p&gt;SQL Change Automation lets DBAs and developers use a migrations-first approach to create precise scripts to apply changes to your database. If you&amp;rsquo;re curious about what I mean by &amp;ldquo;migrations-first&amp;rdquo;, &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/approaches"&gt;read more about this approach, and how it compares to a state-first approach here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working with SQL Change Automation with Git for a while in Microsoft Visual Studio. Visual Studio contains a lot of integration by default with Git and Azure DevOps, so I&amp;rsquo;ve been using its graphical tools, for the most part.&lt;/p&gt;
&lt;h2 id="the-new-sql-change-automation-extension-for-ssms-works-with-the-version-control-system-vcs-of-your-choice-but-this-initial-release-provides-only-working-folder-support"&gt;The New SQL Change Automation Extension for SSMS Works with the Version Control System (VCS) of Your Choice, But This Initial Release Provides Only &amp;ldquo;Working Folder&amp;rdquo; Support&lt;/h2&gt;
&lt;p&gt;That means that you set up your version control outside of SSMS, then point SQL Change Automation at your working folder.&lt;/p&gt;
&lt;p&gt;This inspired me to start learning the Git command line. I&amp;rsquo;m not a command line guru of any sort, but it turns out the Git command line is really easy to learn, and I think it&amp;rsquo;s super fun to use.&lt;/p&gt;
&lt;p&gt;In this 22 minute video, I give an overview of how to create a fresh repo in Azure DevOps and clone it to your local machine, set up a new SQL Change Automation project in SSMS for the Microsoft &lt;a href="https://github.com/microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs"&gt;pubs sample database&lt;/a&gt;, commit changes to source control, work with branches, and stash files away when you need to.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/8BQZuWRw43o?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=40s"&gt;00:40&lt;/a&gt; Where to get &lt;a href="https://github.com/microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs"&gt;the code to create the Pubs database&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=60s"&gt;01:00&lt;/a&gt; Creating a new repo in an Azure DevOps project&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=99s"&gt;01:39&lt;/a&gt; Clone the repo to your local machine with: &lt;strong&gt;git clone urlfromyourrepogoeshere&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=180s"&gt;03:00&lt;/a&gt; &lt;strong&gt;git status&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=210s"&gt;03:30&lt;/a&gt; Create a new SQL Change Automation project and baseline it in SSMS&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=360s"&gt;06:00&lt;/a&gt; Stage the files with: &lt;strong&gt;git add .&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=400s"&gt;06:40&lt;/a&gt; Review staged files with: &lt;strong&gt;git status&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=453s"&gt;07:33&lt;/a&gt; Commit the files with: &lt;strong&gt;git commit -m &amp;ldquo;commit message goes here&amp;rdquo;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=488s"&gt;08:08&lt;/a&gt; Send commit to upstream repo with: &lt;strong&gt;git push&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=582s"&gt;09:42&lt;/a&gt; Create a feature branch with: &lt;strong&gt;git checkout -b foldername/branchname&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=625s"&gt;10:25&lt;/a&gt; Add a new migration script with SQL Change Automation extension in SSMS&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=696s"&gt;11:36&lt;/a&gt; Observe how non-committed files in working directory act in Git when changing branches&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=784s"&gt;13:04&lt;/a&gt; Put away / temporarily remove &amp;ldquo;dirty&amp;rdquo; files with: &lt;strong&gt;git stash -u&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=962s"&gt;16:02&lt;/a&gt; List local branches with: &lt;strong&gt;git branch&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=971s"&gt;16:11&lt;/a&gt; Switch to an existing branch with: &lt;strong&gt;git checkout foldername/branchname&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=977s"&gt;16:17&lt;/a&gt; Unpack / get back your stash with: &lt;strong&gt;git stash pop&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1018s"&gt;16:58&lt;/a&gt; Stage modified files in our feature branch with: &lt;strong&gt;git add .&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1023s"&gt;17:03&lt;/a&gt; Commit modified files in our feature branch with: &lt;strong&gt;git commit -m &amp;ldquo;commit message goes here&amp;rdquo;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1053s"&gt;17:33&lt;/a&gt; Get detailed syntax to push feature branch for the first time to remote repo with: &lt;strong&gt;git push&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1087s"&gt;18:07&lt;/a&gt; View repo in Azure DevOps Services&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1102s"&gt;18:22&lt;/a&gt; View branches and create a pull request to merge our feature branch into master&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1145s"&gt;19:05&lt;/a&gt; Complete pull request, note I use an option that deletes the feature branch on the central repo after merge&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1185s"&gt;19:45&lt;/a&gt; Validate that the feature branch still exists on my client machine with: &lt;strong&gt;git status&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1210s"&gt;20:10&lt;/a&gt; Return to master branch with: &lt;strong&gt;git checkout master&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1222s"&gt;20:22&lt;/a&gt; Clean up my local feature branch with: &lt;strong&gt;git branch -d foldername/branchname&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8BQZuWRw43o&amp;amp;t=1240s"&gt;20:40&lt;/a&gt; Pull down updated code from master with: &lt;strong&gt;git pull&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Key Findings for Database Professionals from the Accelerate State of DevOps Report 2019</title><link>https://kendralittle.com/2019/08/22/key-findings-for-database-professionals-from-the-accelerate-state-of-devops-report-2019/</link><pubDate>Thu, 22 Aug 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/08/22/key-findings-for-database-professionals-from-the-accelerate-state-of-devops-report-2019/</guid><description>&lt;p&gt;The &lt;a href="https://services.google.com/fh/files/misc/state-of-devops-2019.pdf"&gt;Accelerate: State of DevOps Report 2019&lt;/a&gt; has just been published. This report is the latest in six years of research. With more than 31,000 survey responses, &lt;em&gt;Accelerate&lt;/em&gt; is the longest running study of DevOps in academia or industry.&lt;/p&gt;
&lt;p&gt;In the 2019 edition, research continues to show that DevOps drives business value: high performers at DevOps are &amp;ldquo;twice as likely to meet or exceed their organizational goals.&amp;rdquo; While this isn&amp;rsquo;t a new finding, it&amp;rsquo;s very important that this continues to be true: why invest in improving at DevOps if it doesn&amp;rsquo;t drive business value?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-21-08-2019_18-08-41.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;While there are a ton of valuable insights in the report, in this post I will focus in on the findings which I believe are most relevant to those of us who work &amp;ldquo;close to a database.&amp;rdquo; There are three very interesting aspects of the research which hit close to home:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Speed and stability are not tradeoffs&lt;/li&gt;
&lt;li&gt;Heavy change processes negatively impact speed &lt;strong&gt;and stability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Communities of practice are a common and successful tool to transform culture&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="speed-and-stability-enable-one-another"&gt;Speed and Stability Enable One Another&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Accelerate&lt;/em&gt; recommends tracking four key metrics, in addition to availability. Note that half of these are related to speed, and half are related to stability:&lt;/p&gt;
&lt;table class="wp-block-table is-style-regular" style="border: 1px solid black;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="2" align="center" style="border: 1px solid black;"&gt;Speed&lt;/td&gt;&lt;td colspan="2" align="center" style="border: 1px solid black;"&gt;Stability&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid black;"&gt;Lead time for changes&lt;/td&gt;&lt;td style="border: 1px solid black;"&gt;Deployment frequency&lt;/td&gt;&lt;td style="border: 1px solid black;"&gt;Change failure rate&lt;/td&gt;&lt;td style="border: 1px solid black;"&gt;Time to restore service&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Accelerate&lt;/em&gt; explains that the relationship between these metrics is often misunderstood:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many professionals approach these metrics as representing a set of trade-offs, believing that increasing throughput will negatively impact the reliability of the software delivery process and the availability of services. For six years in a row, however, our research has consistently shown that speed and stability are outcomes that enable each other.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Accelerate: State of DevOps 2019, p17&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a tricky thing for IT professionals who have been in the field for a while to get our head around.&lt;/p&gt;
&lt;p&gt;Another way to put this is that, as Microsoft found, &amp;ldquo;&lt;a href="https://myinspire.microsoft.com/sessions/47b1c245-db6b-4e99-b36e-fbbccb013508?source=sessions"&gt;moving fast with poor quality is as bad as moving slow&lt;/a&gt;.&amp;rdquo; A raw deployment count doesn&amp;rsquo;t give any indication of delivery of value. If many of those deployments are doing rework and making up for poor quality, that needs to be factored in, because the point is &lt;a href="http://donovanbrown.com/post/what-is-devops"&gt;delivering&lt;/a&gt; &lt;strong&gt;&lt;a href="http://donovanbrown.com/post/what-is-devops"&gt;value&lt;/a&gt;&lt;/strong&gt; &lt;a href="http://donovanbrown.com/post/what-is-devops"&gt;to customers&lt;/a&gt;: hence the importance of stability metrics.&lt;/p&gt;
&lt;p&gt;The important thing for IT leaders and data professionals to notice is that the evidence has surely piled up that DevOps techniques are a tool that helps us improve stability: and when it comes to data, that&amp;rsquo;s typically one of the biggest areas where a company cares a great deal about maintaining quality and stability.&lt;/p&gt;
&lt;p&gt;There is a clear action for leadership to take here: moving to DevOps means building a team across development and IT silos, and making the metrics above universal outcomes which the entire team moves towards. You must stop rewarding IT based on stability, and stop rewarding software development based on feature delivery: all groups are working towards the full set of metrics.&lt;/p&gt;
&lt;h2 id="heavy-change-processes-negatively-impact-speed-and-stability"&gt;Heavy Change Processes Negatively Impact Speed and Stability&lt;/h2&gt;
&lt;p&gt;IT and database specialists typically act as gatekeepers for production. Traditionally, when things go wrong, heads of IT and their related specialists try to make things better by adding another layer of process to things. This has resulted in complex change approval processes, often including a Change Approval Board.&lt;/p&gt;
&lt;p&gt;As much as we like to think that a complex process will make things better by weeding out problematic deployments, &lt;em&gt;Accelerate&lt;/em&gt; finds that in our attempt to make things better, we&amp;rsquo;re actually making it worse:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;hellip;we investigated whether a more formal approval process was associated with lower change fail rates and we found no evidence to support this hypothesis, consistent with earlier research. We also examined whether introducing more approvals results in a slower process and the release of larger batches less frequently, with an accompanying higher impact on the production system that is likely to be associated with higher levels of risk and thus higher change fail rates. Our hypothesis was supported in the data.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Accelerate: State of DevOps 2019, pages 50-51&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This doesn&amp;rsquo;t mean that you must get rid of change management. Many organizations simply cannot do that due to regulations, and &lt;em&gt;Accelerate&lt;/em&gt; also doesn&amp;rsquo;t suggest that as the path to success.&lt;/p&gt;
&lt;p&gt;But we do need to work towards significantly changing the way that change management and change approvals are done. This includes clarifying change processes to make it incredibly clear to everyone what needs to be done to have a change approved. This also means transforming the jobs of specialists from production gatekeepers into consultants in the software development process: both to build the most effective change process, and to act as peers to review critical changes early in development, and shape the testing strategies for those changes.&lt;/p&gt;
&lt;p&gt;Similarly, leadership on Change Approval Boards should shift into more strategic roles, identifying areas where capabilities are needed the most, and providing guidance and resources on how to improve.&lt;/p&gt;
&lt;p&gt;Changes like this are not going to happen overnight, particularly in larger enterprises. Perhaps this is part of why &lt;em&gt;Accelerate&lt;/em&gt; found this year for the first time that Enterprises, defined as organizations with more than 5,000 employees, comparatively are lower performers than smaller organizations. However, enterprises &lt;em&gt;can&lt;/em&gt; change their culture and processes. On a personal note, I am frequently surprised at the massive level of transformation that I&amp;rsquo;ve observed from my friends who work at Microsoft over the last few years, for example. In an Enterprise situation, the game is about persistence and about seizing promising opportunities to work in new ways.&lt;/p&gt;
&lt;h2 id="communities-of-practice-are-a-common-and-successful-tool-to-transform-culture"&gt;Communities of Practice Are a Common and Successful Tool to Transform Culture&lt;/h2&gt;
&lt;p&gt;One question I often get from database developers or DBAs is how they can convince developers to change their habits in one way or another. This is sometimes phrased as, &amp;ldquo;they don&amp;rsquo;t listen to me.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Accelerate&lt;/em&gt; finds that if you want to change your culture, you&amp;rsquo;re probably going to need to get out of your silo. They asked respondents to share how DevOps and Agile is spread at their organizations, and that found that &amp;ldquo;Low performers tend to favor Training Centers (also known as DOJOS) and Centers of Excellence (CoE): strategies that create more silos and isolated expertise.&amp;rdquo; &lt;em&gt;Accelerate: State of DevOps 2019, p71&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We already have plenty of silos and isolated expertise when it comes to databases, we certainly don&amp;rsquo;t want to create more.&lt;/p&gt;
&lt;p&gt;Instead, tools like Communities of Practice are found to be more effective. 57% of &amp;ldquo;Elite&amp;rdquo; performers were found to use Communities of Practice, the heaviest concentration of any single strategy studied.&lt;/p&gt;
&lt;p&gt;Communities of Practice build both knowledge and community inside organizations. For IT leadership, it&amp;rsquo;s critical to encourage specialist groups in your organization to seed and sponsor these groups, and to participate in them as active community members. For specialists such as DBAs, establishing a Community of Practice around database development is your best tool toward transitioning from being a &amp;ldquo;production gatekeeper&amp;rdquo; into becoming an internal consultant who shapes how database development is done in your organization: a key contributor and collaborator in the software development lifecycle.&lt;/p&gt;
&lt;h2 id="want-more-insights"&gt;Want More Insights?&lt;/h2&gt;
&lt;p&gt;You can download the &lt;a href="http://cloud.google.com/devops/state-of-devops/"&gt;&lt;em&gt;Accelerate: State of DevOps Report 2019&lt;/em&gt;&lt;/a&gt; today.&lt;/p&gt;
&lt;p&gt;Catch a recording of &lt;a href="https://event.on24.com/wcc/r/2067797/C5FA3C28B6227220298169CEECAB6613?partnerref=RGW"&gt;our webinar “What You Need to Know About the 2019 DORA Accelerate State of DevOps Report, with Jez Humble and Steve Jones”&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Azure DevOps: How to Set a Custom Release Branch Folder Filter in Build Pipeline Triggers (Video)</title><link>https://kendralittle.com/2019/08/19/azure-devops-how-to-set-a-custom-release-branch-folder-filter-in-build-pipeline-triggers-video/</link><pubDate>Mon, 19 Aug 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/08/19/azure-devops-how-to-set-a-custom-release-branch-folder-filter-in-build-pipeline-triggers-video/</guid><description>&lt;p&gt;This is the first in a series of posts about simple things that I had a hard time figuring out in Azure DevOps services.&lt;/p&gt;
&lt;p&gt;It can be very useful to enable Continuous Integration for multiple folders in your DevOps pipeline: say, for every branch created under releases/ or features/. But configuring this can be strangely confusing!&lt;/p&gt;
&lt;h2 id="the-solution"&gt;The Solution&lt;/h2&gt;
&lt;p&gt;In this video, I show how to get a custom release branch folder set in your triggers for both build and release pipelines. Then I show a quick test of the automation at work in my demo pipeline.&lt;/p&gt;
&lt;p&gt;Spoiler: the fix is to type directly into the filter box and hit enter. It looks like that box is only for filtering existing branches, but you can use it for edits! The fix starts in the video at 1:50.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/73oi-eXKQd8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>SQL Server Management Studio Is as Relevant as Ever</title><link>https://kendralittle.com/2019/08/14/sql-server-management-studio-is-as-relevant-as-ever/</link><pubDate>Wed, 14 Aug 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/08/14/sql-server-management-studio-is-as-relevant-as-ever/</guid><description>&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;UPDATE&lt;/strong&gt;: Azure Data Studio (ADS) was retired on February 6, 2025, with support ending on February 28, 2026. Additionally, SSMS has been modernized and is no longer based on the legacy Visual Studio shell—it's now built on Visual Studio 2022 with 64-bit support and improved performance.
&lt;BR/&gt;&lt;BR/&gt;
For more details, see the &lt;a href="https://devblogs.microsoft.com/azure-sql/azure-data-studio-retirement/"&gt;Azure Data Studio retirement announcement&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/shows/data-exposed/introducing-ssms-21-preview-data-exposed"&gt;Erin Stellato's announcement about SSMS modernization.&lt;/a&gt;.
&lt;/div&gt;
&lt;p&gt;Sometimes you keep a classic around.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-13-08-2019_19-00-34.jpg"
alt="A well loved skateboard" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;After almost fifteen years of heavy usage by developers and database administrators (DBAs), it might seem like Microsoft’s free tool, &lt;a href="https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms"&gt;SQL Server Management Studio&lt;/a&gt; (SSMS), is about to go out of style.&lt;/p&gt;
&lt;p&gt;After all, SSMS is no longer the cool new kid on the block: Microsoft has shown consistent effort to develop their new tool, &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/what-is"&gt;Azure Data Studio&lt;/a&gt; (the artist formerly known as SQL Operations Studio), since November 2017. Azure Data Studio is built on the modern foundation of Microsoft’s &lt;a href="https://code.visualstudio.com/"&gt;VS Code&lt;/a&gt;, whereas SQL Server Managed Studio is related to the legacy Visual Studio Shell.&lt;/p&gt;
&lt;p&gt;Based on this overview, it might seem like a new SQL Server DBA or developer should primarily learn Azure Data Studio, not SSMS. And it might similarly seem like vendors should focus on developing new tooling only for Azure Data Studio.&lt;/p&gt;
&lt;p&gt;But when you look into the details of how Azure Data Studio is being developed, it becomes clear that SSMS is still just as relevant than ever:&lt;/p&gt;
&lt;h2 id="azure-data-studio-really-shines-where-it-specializes-in-different-functionality-than-ssms-provides"&gt;Azure Data Studio really shines where it specializes in different functionality than SSMS provides&lt;/h2&gt;
&lt;p&gt;While both Azure Data Studio and SSMS each provide an interface to author queries and to execute them against relational database instances, I find that the user experience in Azure Data Studio is often not nearly as smooth as it is in SSMS.&lt;/p&gt;
&lt;p&gt;Where Azure Data Studio really shows its value is in unique experiences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/sql-notebooks"&gt;SQL Notebooks&lt;/a&gt; (based on Jupyter notebooks) which offer an experience of “interactive documentation” and more&lt;/li&gt;
&lt;li&gt;The ability for users to connect, manage, and query different database platforms, using &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/postgres-extension?"&gt;tools like the PostgreSQL extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The ability for MacOS or Linux users to run Azure Data Studio natively, without installing a Windows client&lt;/li&gt;
&lt;li&gt;The ability to work in other languages, &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/powershell-extension"&gt;such as PowerShell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="azure-data-studio-is-being-built-to-sometimes-connect-with-ssms"&gt;Azure Data Studio is being built to sometimes connect with SSMS&lt;/h2&gt;
&lt;p&gt;One Azure Data Studio feature I noticed recently is &amp;ldquo;Release of Database Administration Tool Extensions for Windows&amp;rdquo; &lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/release-notes-azure-data-studio#june-2019"&gt;in June 2019&lt;/a&gt;. Here&amp;rsquo;s the overview of the feature:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This extension launches two of the most used experiences in SQL Server Management Studio &lt;em&gt;from Azure Data Studio&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/azure-data-studio/release-notes-azure-data-studio#june-2019"&gt;Release Notes for Azure Data Studio&lt;/a&gt; (emphasis mine)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a MacOS user, I was slightly disappointed that this is a Windows-only feature: it&amp;rsquo;s Windows-only because it requires that SSMS be installed, so the SSMS feature can be launched inside Azure Data Studio.&lt;/p&gt;
&lt;p&gt;However, I understand where this is coming from: I don’t need &lt;em&gt;every&lt;/em&gt; SSMS feature to work natively in Azure Data Studio on MacOS, and I suspect that this saved a ton of engineering work. If Microsoft plans to support and develop both tools long-term (and I believe this is evidence that they do), it makes sense to strategically create these dependencies.&lt;/p&gt;
&lt;h2 id="ssms-is-still-under-active-development"&gt;SSMS is still under active development&lt;/h2&gt;
&lt;p&gt;A major update to SQL Server Management Studio, SSMS 18.0, released in April 2019. This release included many improvements and new features. New features have been regularly added in the versions since this release as well.&lt;/p&gt;
&lt;p&gt;This pattern shows evidence to support Dinakar Nethi’s suggestion in his &lt;a href="https://cloudblogs.microsoft.com/sqlserver/2019/04/24/sql-server-management-studio-ssms-18-0-released-for-general-availability/"&gt;SSMS 18.0 release announcement&lt;/a&gt; that we should “think of these two tools not as separate tools doing different things, but as one integrated tool. Each tool has different experiences built into it and can be launched from the other seamlessly.”&lt;/p&gt;
&lt;h2 id="users-still-care-a-ton-about-ssms--and-therefore-vendors-care-about-it-as-well"&gt;Users still care a ton about SSMS – and therefore,  vendors care about it as well&lt;/h2&gt;
&lt;p&gt;One comment I have frequently heard over the years from developers and DBAs who work with multiple platforms is that they are impressed by the richness of tooling provided for the Microsoft Data Platform at no extra charge. SSMS provides a very rich experience and covers a vast amount of features – and we users very much enjoy it.&lt;/p&gt;
&lt;p&gt;For this reason, vendors will continue to build new features for SSMS.&lt;/p&gt;
&lt;p&gt;For example, at Redgate, we have just created a major new extension for &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/"&gt;SQL Change Automation in SSMS&lt;/a&gt;, which allows users to author changes in &lt;a href="http://assets.red-gate.com/solutions/database-devops/state-or-migrations-based-database-development.pdf"&gt;a migrations-first approach to development&lt;/a&gt;. We wish to empower teams to collaborate both across Visual Studio and other IDEs, and we recognize that SSMS continues to be the primary tool for Microsoft Data Platform DBAs and many developers – it remains incredibly valuable to offer users the ability to work in SSMS.&lt;/p&gt;
&lt;h2 id="where-do-we-go-from-here"&gt;Where do we go from here?&lt;/h2&gt;
&lt;p&gt;SSMS remains the primary tool for SQL Server specialists. Azure Data Studio is a terrific, complementary tool, with strong use cases for cross-platform experiences and SQL Notebooks.&lt;/p&gt;
&lt;p&gt;For new database administrators working with the Microsoft Data Platform, it continues to make sense to download and learn SSMS first – but do take a few minutes to install both tools and play around with the SQL Notebook functionality in Azure Data Studio specifically, these can be a great tool for you to document information as you learn.  This is also true for developers who need to perform some operational tasks.&lt;/p&gt;
&lt;p&gt;For occasional users who only need to connect to existing instances and run queries, either SSMS or Azure Data Studio is a fine choice.&lt;/p&gt;
&lt;p&gt;For odd users like me, who generally run in a MacOS or Linux environment, and who periodically do more in-depth performance tuning and database management tasks, it’s especially valuable to become fluent in both tools. I love using Azure Data Studio for its Notebook experience and running occasional queries against SQL Server running in Docker on my laptop when appropriate, and only firing up a Virtual Machine to use SSMS when I need a more in-depth experience.&lt;/p&gt;</description></item><item><title>How to Persuade Your Company to Change</title><link>https://kendralittle.com/2019/07/19/how-to-persuade-your-company-to-change/</link><pubDate>Fri, 19 Jul 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/07/19/how-to-persuade-your-company-to-change/</guid><description>&lt;p&gt;Like a lot of developers and database administrators, I do a fair amount of short-term problem solving during the course of my normal work week.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-19-07-2019_18-24-46.jpg" width="250"&gt;
&lt;/figure&gt;
I get to join some Redgate sales calls, often during Proof-of-Concept exercises, and this frequently involves helping brainstorm about the best way to use our tools to solve a specific need for monitoring, database development, or automation. I also pick up customer questions from the &lt;a href="https://dbatools.io/slack/"&gt;#Redgate channel in the SQL Server Community Slack&lt;/a&gt; and &lt;a href="https://forum.red-gate.com/discussion/85596/invoke-databasebuild-with-table-with-a-full-text-index"&gt;answer forum questions&lt;/a&gt; for Redgate when I can.&lt;/p&gt;
&lt;p&gt;Inevitably, when you do a regular amount of troubleshooting and brainstorming with customers, you start to notice patterns and have ideas about how to make things easier, faster, or better in some ways. Sometimes this is an idea for a new process or a new product, or it might be a big change to existing processes or products.&lt;/p&gt;
&lt;p&gt;The challenge is getting it to happen, especially when doing so requires time from your coworkers.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m getting close to my &lt;a href="https://kendralittle.com/2018/08/15/im-joining-redgate-software/"&gt;one year anniversary at Redgate&lt;/a&gt;, which caused me to pause and think critically about the biggest patterns I&amp;rsquo;ve seen with one of my favorite Redgate products: and about some changes I would like to see to make that product even more awesome. (I&amp;rsquo;m not going to tell you what the product or the idea is in this post, by the way. The point is how I&amp;rsquo;m trying to get the idea done.) I realized that this idea is pretty important to me, and I would &lt;em&gt;really&lt;/em&gt; like to see it happen: but it&amp;rsquo;s not a simple or easy thing. So I started to think about what I could do to try to cause some change to happen in this area.&lt;/p&gt;
&lt;h2 id="saying-hey-we-should-do-this-thing-usually-isnt-enough"&gt;Saying, &amp;ldquo;Hey, We Should Do This Thing!&amp;rdquo; Usually Isn&amp;rsquo;t Enough&lt;/h2&gt;
&lt;p&gt;Occasionally, you can successfully initiate change simply by dropping the right idea into the right brains at the right time. But this is pretty rare, in my experience. Usually that &amp;ldquo;right time&amp;rdquo; described is when you can clearly and quickly show that the change will either result in a large amount of revenue immediately, or avoid a disaster which is provably imminent.&lt;/p&gt;
&lt;p&gt;For anything else, even amazing ideas risk falling by the wayside. There are a lot of great ideas out there, but typically all our coworkers and managers already have a direction set for the next few weeks or months, if not longer.&lt;/p&gt;
&lt;p&gt;It takes more than mentioning an idea to get it prioritized, much less actually done. So we need to put in more work to give our great idea a better chance at happening.&lt;/p&gt;
&lt;h2 id="think-about-the-way-your-company-likes-to-communicate"&gt;Think About the Way Your Company Likes to Communicate&lt;/h2&gt;
&lt;p&gt;Company cultures vary quite a bit. If you work at a startup, you&amp;rsquo;re going to pitch ideas quite differently than if you work for a government agency.&lt;/p&gt;
&lt;p&gt;At Redgate, I&amp;rsquo;ve learned that people &lt;em&gt;love&lt;/em&gt; writing and reading. You can see this about us externally by browsing &lt;a href="https://www.red-gate.com/simple-talk/"&gt;Simple Talk&lt;/a&gt;, our &lt;a href="https://www.red-gate.com/hub/product-learning/"&gt;Product Learning articles&lt;/a&gt;, and even &lt;a href="https://documentation.red-gate.com/sca3/developing-databases-using-sql-change-automation"&gt;our product documentation&lt;/a&gt;. We also internally use video quite a bit &amp;ndash; we share video for live meetings and demos, and often share recorded meetings for distributed teams and learning afterward.&lt;/p&gt;
&lt;p&gt;For my pitch, I decided to focus mostly on writing, but to use a bit of recorded video as well. I wrote a paper about the change I was advocating, and why it should be done.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I included in the proposal.&lt;/p&gt;
&lt;h2 id="give-an-executive-summary"&gt;Give an Executive Summary&lt;/h2&gt;
&lt;p&gt;My proposal ended up at around 11 pages, including the table of contents. This is fine for my audience: like I said, Redgaters like writing and research. Even so, not everyone has time to read 11 pages. Even if they do have time, you should start with a pitch about why they should &lt;em&gt;spend&lt;/em&gt; the time with your proposal.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s what an executive summary does. Give a short, high-level, one-paragraph overview of what the problem you&amp;rsquo;re solving is, the impact change will have on your organization, and a suggested course of action.&lt;/p&gt;
&lt;h2 id="explain-the-problem-and-talk-in-dollar-signs-whenever-you-can"&gt;Explain the Problem, and Talk in Dollar Signs Whenever You Can&lt;/h2&gt;
&lt;p&gt;The next thing I did was detail the problem I&amp;rsquo;m solving: what thing or things could be much better? How does my idea relate to those problems?&lt;/p&gt;
&lt;p&gt;In my experience, the more you can quantify the opportunity you see in revenue, and the more specific you can be about that, the more of a response you will get.&lt;/p&gt;
&lt;p&gt;In my case, I explained this in three steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The current experience, and why/where it could be improved&lt;/li&gt;
&lt;li&gt;A list of customers who asked for something related to my idea, or who could / would have benefitted from what I am proposing&lt;/li&gt;
&lt;li&gt;Details on how competing tools measure up in this area&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This wasn&amp;rsquo;t something I did in five minutes: it took several research sessions. I dug through my email and identified some customers that way, and also asked colleagues for examples they remembered. I searched through Salesforce to identify more examples, and also to be able to quantify the size of deals which might be accelerated or created if my idea was implemented. I also did research on competing tools.&lt;/p&gt;
&lt;h2 id="be-open-to-other-solutions"&gt;Be Open to Other Solutions&lt;/h2&gt;
&lt;p&gt;Possibly the hardest part about this whole thing is to not get married to your idea.&lt;/p&gt;
&lt;p&gt;Yes, you&amp;rsquo;re proposing a specific thing. But the really important bit is actually bringing focus to the problem or opportunity that &amp;ldquo;thing&amp;rdquo; addresses. There may be ways this can be approached more quickly, or ways that that address it more thoroughly: possibly those things are even more awesome.&lt;/p&gt;
&lt;p&gt;Because of this, I didn&amp;rsquo;t spend too much time locking my proposal down to the details of the exact thing I&amp;rsquo;m recommending. Instead, I wrote more about the types of functionality that I am proposing, and what customers have told me they want to be able to do quickly and easily: along with some notes about why I believe this is all humanly possible.&lt;/p&gt;
&lt;h2 id="what-happens-next"&gt;What Happens Next?&lt;/h2&gt;
&lt;p&gt;Redgate has a quite open culture. Earlier this week, I shared my proposal out with my team and a few coworkers. Yesterday, I shared it with the stakeholders for the products involved in my idea.&lt;/p&gt;
&lt;p&gt;Today, I got a meeting invite to talk through things with the product teams next week.&lt;/p&gt;
&lt;h2 id="so-youve-got-a-meeting-what-if-nothing-happens"&gt;So You&amp;rsquo;ve Got a Meeting: What If Nothing Happens?&lt;/h2&gt;
&lt;p&gt;As much as I like my idea, it&amp;rsquo;s not something that&amp;rsquo;s likely to happen overnight. It&amp;rsquo;s not a small amount of work, and there&amp;rsquo;s also other awesome things in the works.&lt;/p&gt;
&lt;p&gt;So, even if my idea gets prioritized, I don&amp;rsquo;t consider my proposal to be &amp;ldquo;done.&amp;rdquo; I plan to add more customer use cases to it over time as I come across them, and also to regularly ask other people at Redgate if they have new ideas in this problem space that would make a big difference. Since the bulk of the proposal is written, this maintenance piece is not particularly hard to do, and it will keep my proposal fresh: just right for the exact moment when the stars align and it&amp;rsquo;s the right moment for this change.&lt;/p&gt;
&lt;h2 id="this-isnt-the-only-way-to-inspire-change"&gt;This Isn&amp;rsquo;t the Only Way to Inspire Change&lt;/h2&gt;
&lt;p&gt;The approach that I described here is one that I&amp;rsquo;ve tailored to my situation and my audience. There are other ways to do this.&lt;/p&gt;
&lt;p&gt;For some ideas, you may be able to create a working prototype or proof of concept of what you&amp;rsquo;re talking about: even potentially put it to work on a small scale. When that&amp;rsquo;s possible, you get even better customer stories and an ability to show the potential impact on dollar signs in another way. Absolutely take the option to &amp;ldquo;just get started&amp;rdquo; whenever you can.&lt;/p&gt;</description></item><item><title>Managing Cross-Database Dependencies in Builds (Redgate Video)</title><link>https://kendralittle.com/2019/06/25/managing-cross-database-dependencies-in-builds-redgate-video/</link><pubDate>Tue, 25 Jun 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/06/25/managing-cross-database-dependencies-in-builds-redgate-video/</guid><description>&lt;p&gt;Building your database code is an essential practice to ensure that it compiles from source and that dependencies are met. But things can get tricky when you have objects in some databases which is dependent upon objects in other databases: or even circular dependencies.&lt;/p&gt;
&lt;h2 id="video-overview"&gt;Video Overview&lt;/h2&gt;
&lt;p&gt;In this 20 minute video, I give an overview of the two most popular options that Redgate customers use to manage cross-database dependencies when building SQL Server databases with Redgate&amp;rsquo;s &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/"&gt;SQL Change Automation&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/20xJTUokUxM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>How Developers and DBAs Collaborate in a DevOps World (Video)</title><link>https://kendralittle.com/2019/06/13/how-developers-and-dbas-collaborate-in-a-devops-world-video/</link><pubDate>Thu, 13 Jun 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/06/13/how-developers-and-dbas-collaborate-in-a-devops-world-video/</guid><description>&lt;p&gt;You&amp;rsquo;re a DBA, and your development team is all-in on doing DevOps, and they want to include the database. Should your DBA team limit the permissions or options for automation? Or should you instead re-think how your two teams work together?&lt;/p&gt;
&lt;p&gt;In this 40 minute episode, I discuss DevOps team topologies, the changing role of DBA teams in DevOps, and the opportunities available in creating communities of practice around database development.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: Prefer to listen on the go? You can get this episode on &lt;a href="https://podcasts.apple.com/ca/podcast/dear-sql-dba/id1117507864?mt=2"&gt;iTunes&lt;/a&gt;, &lt;a href="http://dearsqldba.libsyn.com/how-do-developers-and-dbas-collaborate-in-a-devops-world"&gt;download the audio file&lt;/a&gt;, or find Dear SQL DBA in your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WeIASio03vE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="bookmarks-of-topics-covered"&gt;Bookmarks of Topics Covered&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=WeIASio03vE&amp;amp;t=30s"&gt;00:30&lt;/a&gt; - Our question, from a DBA&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=WeIASio03vE&amp;amp;t=420s"&gt;7:00&lt;/a&gt; - Why bother with DevOps?&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=WeIASio03vE&amp;amp;t=563s"&gt;9:23&lt;/a&gt; - Team topologies, aka rethinking how the teams work together. This discussion includes notes on where and when DBAs review changes and talk about architecture in a DevOps way of working.&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=WeIASio03vE&amp;amp;t=1280s"&gt;21:20&lt;/a&gt; - Changing the DBA role from gatekeepers to internal consultants&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=WeIASio03vE&amp;amp;t=1950s"&gt;32:30&lt;/a&gt; - Creating a community of practice&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=WeIASio03vE&amp;amp;t=2318s"&gt;38:38&lt;/a&gt; - Recap and wrap up&lt;/p&gt;
&lt;h2 id="links-from-the-video"&gt;Links from the Video&lt;/h2&gt;
&lt;p&gt;DevOps Topologies - &lt;a href="https://web.devopstopologies.com/"&gt;https://web.devopstopologies.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Communities of Practice - &lt;a href="https://wenger-trayner.com/resources/what-is-a-community-of-practice"&gt;https://wenger-trayner.com/resources/what-is-a-community-of-practice&lt;/a&gt;&lt;/p&gt;</description></item><item><title>A Letter to My 20 Year-Old Self</title><link>https://kendralittle.com/2019/06/11/a-letter-to-my-20-year-old-self/</link><pubDate>Tue, 11 Jun 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/06/11/a-letter-to-my-20-year-old-self/</guid><description>&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tsql2sday150x150_thumb1.jpg"
alt="T-SQL Tuesday logo linking to the month&amp;#39;s topic" width="200"&gt;
&lt;/figure&gt;
&lt;p&gt;This post is a part of &lt;a href="https://twitter.com/search?q=%23tsql2sday&amp;amp;f=live"&gt;#tsql2sday&lt;/a&gt;, a monthly community ritual where a topic is proposed by a community member and everyone is invited to join in.&lt;/p&gt;
&lt;p&gt;This month&amp;rsquo;s topic is from Mohammad Darab, who &lt;a href="https://mohammaddarab.com/t-sql-tuesday-115-dear-20-year-old-self/"&gt;encouraged us to&lt;/a&gt;: &amp;ldquo;Write your 20 year old self a letter. If you could go back in time and give yourself advice, what would it be?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The advice I would give to my 20 year old self is the same advice I give to myself today, more than 20 years later:&lt;/p&gt;
&lt;h2 id="you-are-a-person-who-throws-yourself-into-your-work-all-the-way-into-your-work"&gt;You Are a Person Who Throws Yourself into Your Work: All the Way into Your Work&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-11-06-2019_18-13-00.jpg"
alt="Kendra in her 20&amp;#39;s" width="300"&gt;
&lt;/figure&gt;
&lt;p&gt;You tend to define yourself by your professional activities, and you expect your work to be consistently of very high quality.&lt;/p&gt;
&lt;p&gt;One of your greatest strengths is that you are a creative person, but when you narrow your focus too much, when you make your life too much about work, and when you try to make things &amp;lsquo;perfect&amp;rsquo;, your creativity suffers. Life is a messy business, and to both be productive and to enjoy life, you need to get out of your &amp;ldquo;WORK ROBOT&amp;rdquo; mindset quite often.&lt;/p&gt;
&lt;p&gt;For these reasons, it is important for you to set some boundaries on your work life, and to also put effort into tending to your life outside of work.&lt;/p&gt;
&lt;p&gt;Tactically, this means that you need to practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regularly turning away from work messaging and tasks when you are not at work and not on-call. That email &lt;em&gt;can&lt;/em&gt; wait, no matter what that little voice in your head suggests.&lt;/li&gt;
&lt;li&gt;Finding hobbies and activities outside of the workplace and showing up for them, regularly.&lt;/li&gt;
&lt;li&gt;Staying in communication with your friends and family, and practicing getting back in touch with people you value when you drift apart.&lt;/li&gt;
&lt;li&gt;Saying &amp;ldquo;no&amp;rdquo; at work in a multitude of ways, many of which don&amp;rsquo;t use the word &amp;ldquo;no&amp;rdquo; directly, but do involve you not doing everything yourself. You will feel guilty most times you do this, but that does not mean that the practice is wrong.&lt;/li&gt;
&lt;li&gt;Asking for help at work in a multitude of ways when tasks can&amp;rsquo;t be completed as they were estimated.&lt;/li&gt;
&lt;li&gt;Accepting that &amp;ldquo;good enough&amp;rdquo; is often, in fact, good enough. You will repeatedly be frustrated when you can&amp;rsquo;t make something perfect and when you make mistakes. Often, it is best to own up to the flaws in yourself and the situation and simply accept it, then move on to the next challenge where you may be able to contribute more. Look forward, girl, there&amp;rsquo;s cool stuff ahead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="on-a-personal-level-throughout-the-years-you-will-worry-you-will-worry-a-lot"&gt;On a Personal Level, Throughout the Years You Will Worry: You Will Worry a Lot&lt;/h2&gt;
&lt;p&gt;You will worry about being a nerd, and that you will never really be loved because you are too loud / too fat / too nerdy / too opinionated / not nice enough / not pretty enough / not clever enough / too &amp;lsquo;much&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;You will worry that not everyone likes you, and need to constantly remind yourself that it&amp;rsquo;s fine and right and normal for not everyone to like you, and that &amp;ldquo;being liked&amp;rdquo; is not your measure of success.&lt;/p&gt;
&lt;p&gt;You will struggle to shore up your confidence, again and again.&lt;/p&gt;
&lt;p&gt;You will frequently experience &amp;ldquo;&lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome"&gt;Impostor Syndrome&lt;/a&gt;,&amp;rdquo; and to compensate for this you will tend to spend even more time working, even more time attempting to work on something so hard that it is beyond criticism.&lt;/p&gt;
&lt;p&gt;There is no easy fix for over-worrying. Tending to your non-work life and helping that flourish will help: this wider perspective helps you to better find role models and sponsors, appreciate your strengths, find opportunities to help others, take criticism constructively, let non-constructive trolling roll away into the abyss of the internet, and to enjoy speaking in your own voice.&lt;/p&gt;
&lt;p&gt;But there is no way to banish an over-worrying tendency forever. Learning to let your worries pass instead of clinging onto them like the world&amp;rsquo;s worst life raft will be a life-long project. You will constantly find new tools. You will always need to adapt.&lt;/p&gt;
&lt;p&gt;The good news is that you do seem to love a good long project.&lt;/p&gt;
&lt;p&gt;So get at it, friend. There&amp;rsquo;s still a lot of awesome things to do. Life passes in a flash, but while we are here, we always have the chance to appreciate it and to make it better.&lt;/p&gt;</description></item><item><title>DBAs: Stop Denying Sysadmin to Developers</title><link>https://kendralittle.com/2019/05/30/dbas-stop-denying-sysadmin-to-developers/</link><pubDate>Thu, 30 May 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/05/30/dbas-stop-denying-sysadmin-to-developers/</guid><description>&lt;p&gt;I recently chatted with some folks who have a permissions problem in SQL Server. The permissions problem isn&amp;rsquo;t technical: it&amp;rsquo;s a process problem.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-29-05-2019_18-26-10.jpg"
alt="Photo of a hand with a key in the palm" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;The issue is that these folks are trying to configure a build for their SQL Server databases using Redgate tools, but they aren&amp;rsquo;t allowed sysadmin permissions on &lt;em&gt;any&lt;/em&gt; SQL Server instance in their organization (even in development environments), because of a policy set by the Database Administrators in IT.&lt;/p&gt;
&lt;h2 id="why-do-dbas-deny-sysadmin-permissions-in-development"&gt;Why Do DBAs Deny Sysadmin Permissions in Development?&lt;/h2&gt;
&lt;p&gt;You may find this type of policy puzzling: and for good reason. After all, if you don&amp;rsquo;t trust developers to keep their own development environment running, why would you ever trust any code they&amp;rsquo;ve written enough to deploy it to production?&lt;/p&gt;
&lt;p&gt;In that question is a bit of an answer: this policy occurs when there is &lt;em&gt;a fundamental lack of trust&lt;/em&gt; between development and operations.&lt;/p&gt;
&lt;p&gt;The policy that developers can&amp;rsquo;t have sysadmin rights in development has two main justifications used by database administrators:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Concerns that development environments will drift so far from production standards that they will introduce risks to code quality&lt;/li&gt;
&lt;li&gt;Concerns that allowing any account sysadmin rights in development will lead to application accounts using sysadmin rights in production&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="denying-sysadmin-rights-to-developers-locks-you-into-manually-controlling-environment-drift-instead-of-managing-it-the-smart-way"&gt;Denying Sysadmin Rights to Developers Locks You into Manually Controlling Environment Drift: Instead of Managing It the Smart Way&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve worked in IT or in developing changes for databases for a while, you&amp;rsquo;ve probably come across development database instances that are a complete mess: there are databases with odd names which maybe haven&amp;rsquo;t been used in a long time (but take up a lot of space), jobs failing, low disk space, and settings which resemble nothing in production. This messy type of development instance isn&amp;rsquo;t &lt;em&gt;completely&lt;/em&gt; surprising, because developers need room to experiment.&lt;/p&gt;
&lt;p&gt;Sometimes when the DBAs get called in to help support and instance like this, they respond by locking down permissions. If developers have to &lt;em&gt;ask&lt;/em&gt; to create a database, we won&amp;rsquo;t get unexplained databases, and so on. The idea is to prevent the drift of these shared environments.&lt;/p&gt;
&lt;p&gt;But treating developers like children won&amp;rsquo;t improve the quality of development long term. Removing permissions in development environments instead limits the ability of developers to experiment and automate, and limits the tools you can use to improve code quality.&lt;/p&gt;
&lt;h2 id="how-dbas-should-fix-a-drifted-shared-development-environment-blow-it-up"&gt;How DBAs Should Fix a Drifted Shared Development Environment: Blow It Up&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s true that nobody wants to support a shared development database environment. But here&amp;rsquo;s the thing: &lt;em&gt;you shouldn&amp;rsquo;t even have that shared development environment&lt;/em&gt;. As Troy Hunt explains in &amp;ldquo;&lt;a href="https://www.troyhunt.com/unnecessary-evil-of-shared-development/"&gt;The unnecessary evil of the shared development database&lt;/a&gt;,&amp;rdquo; it makes a lot more sense for each developer to have a dedicated environment to work in.&lt;/p&gt;
&lt;p&gt;One of the things that happens when you develop in a private environment and use standardized practices for your database code is that you &lt;em&gt;automatically&lt;/em&gt; begin to control environment drift, by limiting routes for deployment.&lt;/p&gt;
&lt;p&gt;In this world, there is no &amp;ldquo;wild west&amp;rdquo; shared development environment. Instead you have a workflow like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each developer has a private development environment&lt;/li&gt;
&lt;li&gt;Each developer checks their database code into source control&lt;/li&gt;
&lt;li&gt;Branches in source control are combined with the private development environment to provide isolation / room to experiment for changes (in a way that will not impact other developers)&lt;/li&gt;
&lt;li&gt;When code is ready to be merged in, automated processes build the code: proving that the code in source compiles properly and that all dependencies are met
&lt;ul&gt;
&lt;li&gt;Having sysadmin rights for the process building your code is helpful for flexibility: for example, you might want your build to create a SQL Agent job if it does not exist, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Automation also provides support for deploying that code to a fresh environment for review&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This process emphasizes that development environments need to be able to be quickly reset / recreated whenever needed, and that doing so should not impact other developers.&lt;/p&gt;
&lt;p&gt;This approach also forces developers to ensure that configuration changes are standardized and are handled by code as much as possible, as there is no ability for them to do manual configuration to make the build or review process succeed.&lt;/p&gt;
&lt;p&gt;Most importantly, this approach reduces environment drift while also using automation to &lt;em&gt;improve code quality&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But a key to making this work is allowing high permission right to the accounts which are carrying out the build and other automation.&lt;/p&gt;
&lt;h2 id="what-about-the-possibility-of-a-sysadmin-free-for-all"&gt;What About the Possibility of a &amp;ldquo;Sysadmin Free for All&amp;rdquo;?&lt;/h2&gt;
&lt;p&gt;The other reason this policy creeps up is the idea that developers can&amp;rsquo;t be trusted to follow the &lt;a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege"&gt;principle of least privilege&lt;/a&gt;, and if you give them sysadmin rights for anything they will use it for everything.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume that&amp;rsquo;s a correct assumption for a moment. Giving developers lower privilege won&amp;rsquo;t actually fix the problem if they are always going to configure accounts to have the maximum permission allowed (&amp;ldquo;everything except sysadmin&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;This, again, is an issue of trust.&lt;/p&gt;
&lt;p&gt;The better answer here is not to focus solely on what developer&amp;rsquo;s permissions are in the development environment. The answer is to focus on the permissions that application &lt;em&gt;service accounts&lt;/em&gt; have, and to examine when and how code reviews can make sure that the roles used by service accounts are following the principle of least privilege.&lt;/p&gt;
&lt;h2 id="to-survive-dbas-need-to-stop-being-the-tsa"&gt;To Survive, DBAs Need to Stop Being the TSA&lt;/h2&gt;
&lt;p&gt;We increasingly live in a world where the ability to deliver changes in software quickly, without impacting the user experience, is a core requirement to doing business.&lt;/p&gt;
&lt;p&gt;However, we still live in a world where database administrator groups create policies that slow down development.&lt;/p&gt;
&lt;p&gt;Worse, these policies also prevent the effective use of tools: like automation for builds and deployment of code to fresh environments for review, that &lt;em&gt;improve&lt;/em&gt; code quality and reduce the risk of environment drift.&lt;/p&gt;
&lt;p&gt;If you were a business owner and were investigating how to speed up time to market for your products, would you want your DBA team to be creating and enforcing policies that slow down releases and don&amp;rsquo;t improve quality?&lt;/p&gt;
&lt;p&gt;Or would you be tempted to replace them with a different team, who would invest in using automation to improve code quality as well as improve release tempo?&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t make your organization choose. As DBAs we need to leave our obsession with policies behind, and focus on how to get what we truly want: high quality deployments and efficient management of our environments.&lt;/p&gt;</description></item><item><title>The Best Bit About SQL Saturdays: Nearly Everyone Interacts with Other People</title><link>https://kendralittle.com/2019/05/21/whats-unique-about-sql-saturdays-nearly-everyone-interacts-with-other-people/</link><pubDate>Tue, 21 May 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/05/21/whats-unique-about-sql-saturdays-nearly-everyone-interacts-with-other-people/</guid><description>&lt;p&gt;Today I was looped in on an email thread about the pros and cons of attending a specific event. One person on the thread asked if any of us had attended the event in the past, and whether or not event attendees were engaged with presenters and vendor representatives.&lt;/p&gt;
&lt;p&gt;My immediate thought was: &lt;em&gt;of course&lt;/em&gt; the attendees were engaged, because the event is a &lt;a href="https://sqlsaturday.com/default.aspx"&gt;SQL Saturday&lt;/a&gt;.  I&amp;rsquo;ve never been to a SQL Saturday where the attendees weren&amp;rsquo;t engaged.&lt;/p&gt;
&lt;p&gt;But, I realized that it&amp;rsquo;s a fair question.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/kathi-taking-questions-at-SQL-Saturday-Cambridge.png"
alt="Kathi taking questions at SQL Saturday Cambridge event"&gt;
&lt;/figure&gt;
&lt;h2 id="this-level-of-interaction-isnt-a-given-for-events-much-less-tech-events"&gt;This Level of Interaction Isn&amp;rsquo;t a Given for Events, Much Less Tech Events&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been to other tech events: from free events to very expensive ones, where attendees didn&amp;rsquo;t interact much with anyone else. Mostly people worked away on their laptops/phones/tablets quietly (maybe taking notes, maybe playing Minecraft, hard to say). The speakers seemed a little inaccessible and like they were very busy apart from when they were speaking, and they&amp;rsquo;d generally disappear right after their talk.&lt;/p&gt;
&lt;p&gt;There are definitely a lot of people who attend SQL Saturday events who aren&amp;rsquo;t yet part of the broader SQL Server / Microsoft Data Platform community. They&amp;rsquo;re at a crossroads in their career and they&amp;rsquo;re not completely sure if this technology is for them yet, and they&amp;rsquo;re checking out this free event to see what they might learn from it. But I think the unusual thing about SQL Saturdays is that these events tend to draw these new folks into conversation with people who are already part of the community.&lt;/p&gt;
&lt;h2 id="sql-saturdays-are-very-casual-and-you-dont-need-to-act-like-an-expert"&gt;SQL Saturdays Are Very Casual, and You Don&amp;rsquo;t Need to Act Like an Expert&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s traditional for speakers at SQL Saturdays to encourage questions and comments, and usually at SQL Saturdays there is no lack of attendee questions.&lt;/p&gt;
&lt;p&gt;At some tech events, nobody ever &amp;ldquo;breaks the ice&amp;rdquo; during sessions by asking a question that&amp;rsquo;s accessible to beginners, and it can be tough to get the audience to ask questions or make comments. (Aside: if you are a speaker and would like me to ask a dumb question* from the audience to break the ice in your session, I am happy to do so! I am proud to provide this free service anytime I am around.) I&amp;rsquo;ve never found &amp;ldquo;too much quiet&amp;rdquo; to be a problem with SQL Saturdays, even at the events in countries where people are traditionally more reserved. I attended a lunchtime session at a SQL Saturday in Cambridge where &lt;a href="https://twitter.com/GFritchey"&gt;Grant Fritchey&lt;/a&gt; got a room full of British people to share their experiences and pain points throughout the whole hour.&lt;/p&gt;
&lt;p&gt;SQL Saturday organizers are also very good at packing their schedules with a variety of sessions that are quite accessible for people at different phases of their career and different experience levels, which helps everyone find content they can relate to.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;On dumb questions&lt;/strong&gt;: what I generally mean by a "dumb question" is one that makes the asker sound like a bit of a newbie / beginner / person who isn't in-the-know. I have become a person who loves to ask these, because having the question asked and answered thoughtfully often changes the dynamic in the room and makes it OK for everyone else to be a bit more vulnerable.
&lt;/div&gt;
&lt;h2 id="a-huge-factor-is-that-people-in-the-sql-saturday-community-are-extremely-welcoming"&gt;A Huge Factor Is That People in the SQL Saturday Community Are Extremely Welcoming&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a certain community vibe at the event that I think newcomers often feel and want to be part of. You see people who are chatting about what they&amp;rsquo;re up to, their experiences, and what they want to learn, and it&amp;rsquo;s natural to want to be a part of that.&lt;/p&gt;
&lt;p&gt;I tend to take this community vibe, and in fact the supportiveness of the whole SQL Server community for granted, most of the time. But it&amp;rsquo;s a real thing, and it&amp;rsquo;s great to be a part of.&lt;/p&gt;
&lt;h2 id="so-what-are-you-waiting-for"&gt;So, What Are You Waiting For?&lt;/h2&gt;
&lt;p&gt;If you haven&amp;rsquo;t been to a SQL Saturday and you&amp;rsquo;re reading this, &lt;a href="https://sqlsaturday.com/default.aspx"&gt;check out SQLSaturday.com&lt;/a&gt; and look for SQL Saturday events in your area or your region. Even if you&amp;rsquo;re not committed to working in the Microsoft data platform. Even if you&amp;rsquo;re just a little bit curious about learning something for free on a Saturday. It&amp;rsquo;s a wonderful event, and it makes it easy for you to meet new people, to check out all sorts of new things, and to get engaged with the community of people involved in the Microsoft Data Platform.&lt;/p&gt;
&lt;p&gt;I hope to see you at an event soon.&lt;/p&gt;</description></item><item><title>How to Recognize the Early Stages of Burnout, and My Treatment Plan</title><link>https://kendralittle.com/2019/05/14/how-to-recognize-the-early-stages-of-burnout-and-my-treatment-plan/</link><pubDate>Tue, 14 May 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/05/14/how-to-recognize-the-early-stages-of-burnout-and-my-treatment-plan/</guid><description>&lt;p&gt;I recently realized that I&amp;rsquo;m in the early stages of burnout.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t an unfamiliar place for me, but it is new for me to recognize the early signs of burnout in myself &lt;em&gt;before&lt;/em&gt; it becomes a full-fledged disaster. This time, I&amp;rsquo;m thinking about how I got here, and making an explicit plan to change course.&lt;/p&gt;
&lt;p&gt;In hope of helping someone else out there, I thought some public journaling might be in order.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-07-05-2019_21-17-42.jpg"
alt="Photo of a bus interior with the phrase &amp;#39;welcome to the struggle bus&amp;#39;"&gt;
&lt;/figure&gt;
&lt;h2 id="how-do-you-recognize-if-youre-in-the-early-stages-of-burnout"&gt;How Do You Recognize If You&amp;rsquo;re in the Early Stages of Burnout?&lt;/h2&gt;
&lt;p&gt;I have recognized two symptoms which I identify as unusual for me. Together they indicate I&amp;rsquo;m heading towards burnout.&lt;/p&gt;
&lt;h3 id="symptom-1-lately-i-get-frustrated-and-angry-by-small-things"&gt;Symptom 1: Lately, I get frustrated and angry by small things&lt;/h3&gt;
&lt;p&gt;One warning sign of burnout is when small inconveniences start causing a disproportionately large emotional response.&lt;/p&gt;
&lt;p&gt;For example, on a recent weekend I was traveling for work. I was in the Detroit area, about to head to London between a client visit and a conference. It was a beautiful day. I stopped by a local Starbucks and, by chance, another customer was rude to me.&lt;/p&gt;
&lt;p&gt;Normally, if I wasn&amp;rsquo;t in the early stages of burnout, I would assume the other person was having a bad day, and I&amp;rsquo;d shrug this off. It wouldn&amp;rsquo;t be something that I&amp;rsquo;d even be likely to remember. But in this case, I felt a lot of anger toward that person. I was &lt;em&gt;livid&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I quickly realized that the way I was feeling was more about me than about that random person in the Starbucks, but it took me a long time to shake off the anger.&lt;/p&gt;
&lt;p&gt;This aspect of burnout is particularly tricky, because natural little miscommunications at work can slow you down more than normal, as you&amp;rsquo;re now having to handle not just the miscommunication, but also keep your own stress and irritability in check.&lt;/p&gt;
&lt;h3 id="symptom-2-lack-of-excitement"&gt;Symptom 2: Lack of excitement&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m also just not as interested in work projects as normal. I&amp;rsquo;ve got a lot scheduled, but I often feel like I&amp;rsquo;m overwhelmed, and that all I can do is the bare minimum.&lt;/p&gt;
&lt;p&gt;This lack of excitement contributes to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Less curiosity and asking fewer questions&lt;/li&gt;
&lt;li&gt;Taking less time to connect with my teammates and chat&lt;/li&gt;
&lt;li&gt;Poorer listening skills&lt;/li&gt;
&lt;li&gt;More hurried work / less critical thinking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those things together mean that my work quality goes down a bit. And then &lt;em&gt;that&lt;/em&gt; frustrates me.&lt;/p&gt;
&lt;h2 id="what-causes-me-to-burn-out"&gt;What Causes Me to Burn Out?&lt;/h2&gt;
&lt;p&gt;Like I said, I&amp;rsquo;ve been here before: and I&amp;rsquo;ve been past this point, to where I simply couldn&amp;rsquo;t cope with the stress of my daily job anymore. Looking back, I can see some trends.&lt;/p&gt;
&lt;p&gt;I have a tendency to enjoy working a little too much. And I have a few traits that I believe pave the way to burnout:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I tend to be a perfectionist, and I always want to help.&lt;/strong&gt; I don&amp;rsquo;t like saying no, I always want to be involved when asked. I like finding a way to not only make things work, but to try to give them an interesting twist, too. I spend more hours working than I should: and by saying, &amp;ldquo;more hours than I should,&amp;rdquo; I mean&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I haven&amp;rsquo;t been giving myself enough time to recharge.&lt;/strong&gt; For good health, I need to spend time away from a computer. I need to get exercise. I need to spend time outside. Meditating on a daily basis helps me ward off anxiety. Spending time with friends in person really helps as well. One of the things I realize now is that I haven&amp;rsquo;t been doing enough of these things lately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I stretched myself thin and didn&amp;rsquo;t leave any room for life to happen.&lt;/strong&gt; I signed up for a few more work projects than I should have this spring and summer. They are awesome projects, they are interesting and exciting and important. But I maxed out my schedule (plus a little), complete with loads of travel. It looked barely doable: until my dog, Mister, unexpectedly passed away. There was no room in my busy schedule for me to grieve my best doggo friend, and he wasn&amp;rsquo;t there to wag and say it&amp;rsquo;d all be great anymore. I started to feel trapped.&lt;/p&gt;
&lt;h2 id="-perfectionist--overcommitment----self-care---grief--tire-fire"&gt;(( Perfectionist + Overcommitment ) - Self-Care ) × Grief = Tire Fire&lt;/h2&gt;
&lt;p&gt;As a career Ops person, I always want leeway. I like to plan a course where I&amp;rsquo;ve got a backup plan in my back pocket, and ideally a few viable alternatives behind that.&lt;/p&gt;
&lt;p&gt;When you are headed towards burnout, you start feeling like there&amp;rsquo;s no leeway. No alternate plans. You have more stress than you can handle. You&amp;rsquo;ve got a seat on the struggle bus, and you&amp;rsquo;re not sure who is driving it.&lt;/p&gt;
&lt;p&gt;So, what to do to change course?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my plan.&lt;/p&gt;
&lt;h2 id="step-1-book-time-off"&gt;Step 1: Book time off&lt;/h2&gt;
&lt;p&gt;Yes, I am presently oversubscribed. But the very first thing I did when I recognized that I&amp;rsquo;m heading towards burnout was that I went into my calendar and started requesting days off wherever I could possibly make it work, or where someone else might be able to make it work in my absence.&lt;/p&gt;
&lt;p&gt;This sounds counter-intuitive, but it&amp;rsquo;s necessary. While I can&amp;rsquo;t take a week or two weeks off right now, what I can do is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make a proposal for days off&lt;/li&gt;
&lt;li&gt;Explain why I&amp;rsquo;m asking for those days off to my colleagues and boss, and ask for help to make it happen&lt;/li&gt;
&lt;li&gt;Commit to &lt;em&gt;not working&lt;/em&gt; during that time off: no notifications, no emails, nothing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oddly enough, I find that it&amp;rsquo;s harder to disconnect from work than normal when I&amp;rsquo;m close to burnout. It&amp;rsquo;s something about the stress: it makes it harder to put work down. But disconnecting is truly needed, and for me I think this is one of the biggest ways to avoid burnout.&lt;/p&gt;
&lt;p&gt;Putting work on pause and having time off helps give needed perspective on life. It reduces stress, eases the tension causing those knee jerk reactions.&lt;/p&gt;
&lt;p&gt;It will also pay itself back by helping make me more focused and efficient when I am at work.&lt;/p&gt;
&lt;h2 id="step-2-spend-time-with-humans-of-the-non-work-variety"&gt;Step 2: Spend time with humans (of the non-work variety)&lt;/h2&gt;
&lt;p&gt;The second thing I did after recognizing the symptoms of burnout was to email my friends at home and suggest getting together. I was lucky to have a good friend who had just started up a conversation about this, but I looked around at my other friendships and thought about others who I haven&amp;rsquo;t seen in a while, as well.&lt;/p&gt;
&lt;p&gt;As an adult, it can be tough to make and maintain friendships. But the time and effort is so worth it. For me, it makes me a happier person, and that happiness extends into my work life.&lt;/p&gt;
&lt;p&gt;Just like disconnecting from work, shifting gears and making time for friendships can be a mentally tough thing when you&amp;rsquo;re feeling burnt out. My mind tends to fixate on the problems at work, and it wants to stay there.&lt;/p&gt;
&lt;p&gt;But I know from experience that planning a hike with a buddy is so much better for me in the long run, so a big part of my &amp;ldquo;anti-burnout&amp;rdquo; plan is making sure that I&amp;rsquo;m getting at least four hours of non-nerd-time human contact a week for the next few months. (I know, it&amp;rsquo;s just so &amp;ldquo;perfectionist&amp;rdquo; of me to set an hourly goal, right? I like specific targets.)&lt;/p&gt;
&lt;h2 id="step-3-pick-an-anti-anxiety-habit-or-two"&gt;Step 3: Pick an anti-anxiety habit (or two)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;For me, daily meditation is very helpful.&lt;/strong&gt; I have learned in the past that this is a simple tool that is quite effective at reducing my stress and anxiety. When I start doing this on a daily basis, it has a more significant effect each day.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m starting this slowly at just five minutes a day of meditation. At first my whole goal is simply to re-establish this as a habit, without mentally scolding myself if I skip a day. The point is to keep starting until it becomes something that I look forward to each day and it is once again natural.&lt;/p&gt;
&lt;p&gt;I find that when I do practice meditation, I have a more balanced view of things and I am more able to ask for help. I&amp;rsquo;m also better at thinking of alternatives for how something could work when someone has a request that I can&amp;rsquo;t fulfill due to time commitments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Journaling is also helpful for me.&lt;/strong&gt; I&amp;rsquo;ve started writing for this blog in a new way. I&amp;rsquo;m finding that it&amp;rsquo;s helpful in a similar way that journaling helps me think through things.&lt;/p&gt;
&lt;p&gt;For example, I dictated the first draft of this blog post aloud while walking around a hotel room looking out the window. An app on my phone recorded the audio and uploaded it to the cloud. Another app created a transcript, which I edited for the post.&lt;/p&gt;
&lt;p&gt;This method encourages me to be more conversational and more personal in my writing.  That&amp;rsquo;s very very helpful for me right now, because it&amp;rsquo;s a little bit more about my experiences and it&amp;rsquo;s a little bit more about getting my thoughts out in a way that is helpful and therapeutic for me. It also just makes me more excited about writing again, which is incredibly welcome.&lt;/p&gt;
&lt;h2 id="what-if-i-dont-have-time"&gt;What if I don&amp;rsquo;t have time?&lt;/h2&gt;
&lt;p&gt;The voice of burnout in your head is likely to make an objection: &lt;em&gt;we don&amp;rsquo;t have time for this. That&amp;rsquo;s the whole point.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, here&amp;rsquo;s the thing that I&amp;rsquo;ve learned from the past: it may hurt to make time, but it&amp;rsquo;s going to hurt even more if you don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not easy to ask for help with your workload. You may need to negotiate to make it happen. It&amp;rsquo;s not a good feeling to say that you can&amp;rsquo;t do things which you&amp;rsquo;ve agreed to. If you&amp;rsquo;re in a culture of over-achievers, it can be quite difficult to say that you don&amp;rsquo;t want to work as much as everyone else is working.&lt;/p&gt;
&lt;p&gt;However, the thing about burnout is that &lt;em&gt;you can&amp;rsquo;t sustain it&lt;/em&gt;. If you don&amp;rsquo;t take action and you just keep your nose to the grindstone, chances are good that you&amp;rsquo;ll become desperate for a job change, and that you&amp;rsquo;ll either quit your job or take something, anything, for a change.&lt;/p&gt;
&lt;p&gt;Burnout leads to bad choices.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a much better choice to start doing the tough work and speak up for your own needs, before you are so burned out that you can&amp;rsquo;t. Get yourself into a more productive place before making any big decisions about the future: and things &lt;em&gt;will&lt;/em&gt; look better from your new vantage point.&lt;/p&gt;</description></item><item><title>Paying Down Technical Debt</title><link>https://kendralittle.com/2019/05/07/paying-down-technical-debt/</link><pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/05/07/paying-down-technical-debt/</guid><description>&lt;p&gt;One of the cool things that I do as an Evangelist at &lt;a href="https://www.red-gate.com/"&gt;Redgate&lt;/a&gt; is to periodically visit company headquarters in Cambridge.&lt;/p&gt;
&lt;p&gt;The other Evangelists and I get to meet with every software developer, product manager, and UX designer at Redgate over a series of meetings. We talk about features that teams have released lately and what teams are looking at doing in the near future. We get to give feedback based on what we hear from the community and from folks in the sales process. We also get to share what we think teams should work on.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-23-04-2019_17-39-55.jpg"
alt="Photo of a brick wall with &amp;#39;until debt tear us apart&amp;#39; spray painted on it in block letters" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="as-you-might-imagine-i-have-a-wish-list-for-features-in-a-variety-of-different-redgate-products"&gt;As You Might Imagine, I Have a Wish List for Features in a Variety of Different Redgate Products&lt;/h2&gt;
&lt;p&gt;Our products are great, and one of the things about great products is that users are always inspired to want to use them in new ways, so I never lack for ideas.&lt;/p&gt;
&lt;p&gt;So, I have a lot of opinions about things that I think should happen, and features that I would love to have for customers. And, of course, I&amp;rsquo;d like those features &lt;em&gt;right now&lt;/em&gt;, please.&lt;/p&gt;
&lt;h2 id="in-a-recent-meeting-with-one-of-the-teams-they-mentioned-that-most-of-their-work-over-the-next-couple-of-sprints-involves-working-on-their-continuous-integration-process"&gt;In a Recent Meeting with One of the Teams, They Mentioned That Most of Their Work Over the Next Couple of Sprints Involves Working on Their Continuous Integration Process&lt;/h2&gt;
&lt;p&gt;This sounds like a bummer, right? It&amp;rsquo;s a time period when the features on my wishlist, and &lt;a href="https://twitter.com/way0utwest"&gt;Steve&lt;/a&gt;&amp;rsquo;s wishlist, and &lt;a href="https://twitter.com/GFritchey"&gt;Grant&lt;/a&gt; and &lt;a href="https://twitter.com/auntkathi"&gt;Kathi&lt;/a&gt;&amp;rsquo;s wish lists aren&amp;rsquo;t getting worked on.&lt;/p&gt;
&lt;p&gt;But what the team explained was that this application has been around for a while, and a large amount of tests have accumulated. It currently takes more than 10 hours for the build and test process to run. There may be duplicate work going on in the tests, and there are probably tasks that can be made much more efficient. The long build and test time currently makes it painfully slow for the team to iterate on developing and testing new features. &lt;/p&gt;
&lt;p&gt;The team said that in the long run it&amp;rsquo;s worth paying down some debt and making the automated build and testing cycle more efficient, so that they can iterate on features faster in the future, instead of having to find other things to do while waiting for the CI process to complete.&lt;/p&gt;
&lt;p&gt;This news wasn&amp;rsquo;t greeted with cheers from all the Evangelists present: but, to be fair, when we do respond to something with cheers it makes some of the teams look at us oddly, as we&amp;rsquo;re in the UK and that&amp;rsquo;s not something they see every day at work. (Hey, I bring my American enthusiasm everywhere!)&lt;/p&gt;
&lt;p&gt;But everyone in the room agreed that speeding up the build and test cycle as much as possible is a necessary and reasonable thing to do&lt;/p&gt;
&lt;p&gt;Like any other set of users, we want what we want (and we want it ASAP), but we respect that to make software development work well, you occasionally have to step back and pay down some technical debt.&lt;/p&gt;
&lt;h2 id="this-is-also-true-for-database-development"&gt;This Is Also True for Database Development&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not always obvious that when doing DevOps, stability is just as important as release frequency, but that is the case, and maintaining that stability requires being diligent about tidying up one&amp;rsquo;s processes.&lt;/p&gt;
&lt;p&gt;As database professionals, as developers and DBAs, I believe what we should see as the ideal release cycle is one in which we are free to release features every day without any manual work, and we have a software development cycle in place that ensures that the risk of our changes is minimized, that coding patterns are being used that ensure system stability, and that we have a response process in place that restores services as quickly as needed should there be a performance, availability, or functionality problem.&lt;/p&gt;
&lt;p&gt;But that doesn&amp;rsquo;t mean that we &lt;em&gt;actually&lt;/em&gt; release changes every single day. In order to do that effectively, we usually have to have paid down a lot of technical debt. That means stepping back periodically and working on improving our processes, rather than relentlessly focusing on shipping, shipping, shipping, shipping.&lt;/p&gt;
&lt;h2 id="this-is-even-more-critical-with-legacy-applications-where-there-is-a-significant-amount-of-technical-debt-to-pay-down"&gt;This Is Even More Critical with Legacy Applications, Where There Is a Significant Amount of Technical Debt to Pay Down&lt;/h2&gt;
&lt;p&gt;Spending release cycles on making continuous integration and continuous delivery/deployment work better isn&amp;rsquo;t the part of DevOps that gets business owners and users really excited. But it&amp;rsquo;s still important to talk about, because this is a critical activity that enables us to deliver value on a regular basis: and that &lt;em&gt;is&lt;/em&gt; what gets those folks excited.&lt;/p&gt;</description></item><item><title>What Is Automation in the Software Development Life Cycle?</title><link>https://kendralittle.com/2019/04/29/what-is-automation-in-the-software-development-life-cycle/</link><pubDate>Mon, 29 Apr 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/04/29/what-is-automation-in-the-software-development-life-cycle/</guid><description>&lt;p&gt;Today I got a bit closer to a meaningful definition of automation, as it applies to the software development process. I&amp;rsquo;ve been turning this concept over in my head for a while, which is partly related to the dreaded question of licensing.&lt;/p&gt;
&lt;h2 id="why-should-licensing-an-automation-product-be-related-to-the-number-of-users"&gt;Why Should Licensing an Automation Product Be Related to the Number of Users?&lt;/h2&gt;
&lt;p&gt;A few weeks ago, I was chatting a bit in the SQL Server Community Slack Channel. One community member was frustrated with running into situations with per-user licensing for monitoring and automation products.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;On the SQL Server Community Slack channel&lt;/strong&gt;: The SQL Server Community Slack channel is great, &lt;a href="https://dbatools.io/slack/"&gt;join up here&lt;/a&gt;.
&lt;/div&gt;
&lt;p&gt;This isn&amp;rsquo;t the first time I&amp;rsquo;ve heard grumbling about per-user licensing, of course: with &lt;strong&gt;any&lt;/strong&gt; licensing model, you&amp;rsquo;re going to hear grumbling about it, that&amp;rsquo;s just how licensing goes.&lt;/p&gt;
&lt;p&gt;But I think per-user licensing can make a lot of sense when it comes to automation products, because of the nature of automation. I work for &lt;a href="https://www.red-gate.com/"&gt;Redgate&lt;/a&gt;, which does per-user licensing. I also often do demos of how our tools integrate with Microsoft&amp;rsquo;s &lt;a href="https://azure.microsoft.com/en-us/pricing/details/devops/azure-devops-services/"&gt;Azure DevOps Services&lt;/a&gt; (formerly VSTS / or TFS-in-the-cloud), which does licensing based on user numbers.&lt;/p&gt;
&lt;p&gt;But not everyone thinks this makes sense.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because they see automation as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Something that &lt;strong&gt;one person&lt;/strong&gt; sets up on a server, which that person may occasionally tweak; and&amp;hellip;&lt;/li&gt;
&lt;li&gt;A script or orchestrated set of scripts and products that replace the work that people (maybe more people than the person who set it up) would do manually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This definition isn&amp;rsquo;t dumb or naive at all. This is classically what automation &lt;strong&gt;has been&lt;/strong&gt; in IT for many years: I&amp;rsquo;ve got a problem. I create a script. The script helps save me and my team some time and I only ever look at it again if it stops working.&lt;/p&gt;
&lt;p&gt;Based on that definition, it would seem most natural way to be charged for automation tools would be based on something like the number of times the tools are run, the number of servers/cores they are run on, etc.
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/photo-1522051311534-1f53d56b49df.jpeg"
alt="Drawing of a robot on a whiteboard in white marker." width="230"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id="the-nature-of-automation-has-changed-dramatically-in-recent-years"&gt;The Nature of Automation Has Changed Dramatically in Recent Years&lt;/h2&gt;
&lt;p&gt;Like I said, I&amp;rsquo;ve been having a hard time putting a definition of what automation means &lt;strong&gt;now&lt;/strong&gt; into words. Then I saw a link to &lt;a href="https://jobs.netflix.com/jobs/869465"&gt;this job description for a Sr. Resilience Engineering Advocate at Netflix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are a lot of interesting things about the job description, but one sentence that leapt off the page to me was that the team values:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Automation as a team player versus automation as a replacement for humans&lt;/p&gt;
&lt;p&gt;Netflix Cloud and Platform Engineering SRE Team&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a huge part of the evolving definition of automation. Automation is now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Something that a &lt;strong&gt;team&lt;/strong&gt; configures, interacts with, and improves on a daily basis&lt;/li&gt;
&lt;li&gt;A script or orchestrated set of scripts and products that are an integral part of the productivity of the team&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The big reason that per-user licensing makes logical sense to me when it comes to tools that are designed to be a key part of the software development life cycle is that the tools are meant to be experimented with freely. The tools will work best if they&amp;rsquo;re able to be tinkered with and adapted over time, to suit the needs of the team at that point. Licensing based on cores or CPU cycles or usage naturally reduces experimentation if it is going to drive up cost.&lt;/p&gt;
&lt;p&gt;Also, the tools are meant to be team players: they are meant to be available to have every team member interact with them. Automation in the SDLC for database changes doesn&amp;rsquo;t mean that every time a change is committed, the change rockets toward production without a human being ever needing to think about it again. Instead, automation is a player in a process that can absolutely include rigorous review (both automated and human-powered), testing, and even approval gates when needed.&lt;/p&gt;
&lt;h2 id="automation-looks-different-in-different-teams"&gt;Automation Looks Different in Different Teams&lt;/h2&gt;
&lt;p&gt;One observation: team size matters. If you&amp;rsquo;re one person in a small shop and you&amp;rsquo;re setting up automation to reduce the amount of manual work that you personally have to do, this high-faultin&amp;rsquo; definition of automation as a &amp;ldquo;team player&amp;rdquo; probably isn&amp;rsquo;t going to resonate with you. You&amp;rsquo;re much more likely to continue to see automation in the classically defined sense.&lt;/p&gt;
&lt;p&gt;But, on the other hand, you don&amp;rsquo;t have to have a team &lt;strong&gt;nearly&lt;/strong&gt; as large as Netflix to start seeing the advantages of thinking about automation differently. It just takes a few people working together collaboratively and thinking about how to more consistently and reliably deliver values to customers to start changing the way automation exists in the workplace.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;On licensing costs&lt;/strong&gt;: I don't mean to make this post about how much software should cost. I actually don't think that's too terribly related to licensing model choice at all: whatever you are charging by, whether it be people, cores, tentacles, or whatnot, you can find a way to make it cheaper or more expensive.
&lt;/div&gt;</description></item><item><title>Should Release Cadence Be Slowed If You Don't Have Database Load Testing?</title><link>https://kendralittle.com/2019/04/23/should-release-cadence-be-slowed-if-you-dont-have-database-load-testing/</link><pubDate>Tue, 23 Apr 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/04/23/should-release-cadence-be-slowed-if-you-dont-have-database-load-testing/</guid><description>&lt;p&gt;I got a question recently about &lt;a href="https://www.youtube.com/watch?v=yB5uM7Hr74Y"&gt;a panel discussion on Database Development Disasters at SQL in the City Streamed&lt;/a&gt;. I had framed a question as, &amp;ldquo;how fast should development go without load or performance testing?&amp;rdquo;&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-22-04-2019_18-43-42.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I got a follow-up question from my friend &lt;a href="https://www.linkedin.com/in/chris-randvere-689080a/"&gt;Chris Randvere at Redgate&lt;/a&gt;: he asked for more information about what the question meant? I realized that my wording had been pretty unclear. I had meant to ask the panelists what their thoughts were on release cadence when a team lacks tooling to do automated load and performance testing outside of production.&lt;/p&gt;
&lt;h2 id="should-the-lack-of-automated-performance-testing-ability-change-the-rate-at-which-we-deploy-software"&gt;Should the Lack of Automated Performance Testing Ability Change the Rate at Which We Deploy Software?&lt;/h2&gt;
&lt;p&gt;In other words, if we can&amp;rsquo;t do performance and load testing, does that mean that we should or shouldn&amp;rsquo;t deploy a change to a database every weekday?&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think we covered this super-well in the panel because I worded the question poorly. So I wanted to share my experience around this, and also talk about why it can be fairly common for teams to lack automated load testing ability outside of production.&lt;/p&gt;
&lt;h2 id="why-doesnt-everyone-have-an-environment-where-they-can-validate-performance-by-replaying-activity-against-an-updated-database-before-it-ever-gets-released"&gt;Why Doesn&amp;rsquo;t Everyone Have an Environment Where They Can Validate Performance by Replaying Activity Against an Updated Database Before It Ever Gets Released?&lt;/h2&gt;
&lt;p&gt;We have some built-in tools for this in SQL Server. The current version of this is called &lt;a href="https://docs.microsoft.com/en-us/sql/tools/distributed-replay/sql-server-distributed-replay"&gt;Distributed Replay&lt;/a&gt;. These tools are not the most lovingly tended by Microsoft in terms of updates. A frequent complaint that I&amp;rsquo;ve heard about distributed replay is that the current version of the tooling still requires you to feed it with old style profile traces done with the old SQL Trace.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t necessarily have to have the Profiler app running while you do the trace, but the old-style SQL Trace results are what it takes in in other words. You can&amp;rsquo;t do a more modern Extended Events trace and feed that into the tool.&lt;/p&gt;
&lt;p&gt;But that lack of updates isn&amp;rsquo;t the main reason why not everyone runs Distributed Replay.&lt;/p&gt;
&lt;h3 id="distributed-replay-is-tricky-to-set-up"&gt;Distributed Replay Is Tricky to Set Up&lt;/h3&gt;
&lt;p&gt;The more complex your environment, the trickier it is to set it up. If you&amp;rsquo;ve got things like linked servers or SQL Server transactional replication creating interesting patterns in which your SQL Server communicates with other SQL Servers, that can make using Distributed Replay particularly tricky.&lt;/p&gt;
&lt;p&gt;There are absolutely people out there who&amp;rsquo;ve configured Distributed Replay on complex systems, but they all say it wasn&amp;rsquo;t something they set up in just two hours. So one factor is the complexity.&lt;/p&gt;
&lt;h3 id="another-factor-distributed-replay-is-designed-to-replay-not-to-amplify"&gt;Another Factor: Distributed Replay Is Designed to Replay, Not to Amplify&lt;/h3&gt;
&lt;p&gt;When we&amp;rsquo;re doing performance or load testing, we are not always interested in: how will the system perform under the current load? A lot of times we&amp;rsquo;re interested in: how will the system perform if it&amp;rsquo;s under even more load? 150% of the load, or 200%, or more.&lt;/p&gt;
&lt;p&gt;But with any replay tool: I&amp;rsquo;m not just dogging on distributed replay here, if we think about the nature of any database replay tool, we can&amp;rsquo;t replay the exact same commands and expect to learn how performance will be at a higher load rate.&lt;/p&gt;
&lt;p&gt;For example, a delete command. If a delete command on the first run finds 10,000 rows to delete, that could be a fair amount of work.&lt;/p&gt;
&lt;p&gt;If we replay that same delete command, depending on what the criteria are in the delete, it possibly will find zero rows to delete the second time, because it&amp;rsquo;s already completed. Similar things can happen with updates. We may also have constraints that mean we can&amp;rsquo;t just insert the same thing twice depending on the nature of the data.&lt;/p&gt;
&lt;p&gt;So the way modifications work, just amping up the load in a replay isn&amp;rsquo;t the same as adding &lt;em&gt;true&lt;/em&gt; additional load.&lt;/p&gt;
&lt;p&gt;Now, there are other ways you can do load testing. There are third-party tools that you can buy to get around this problem of repeated modifications.&lt;/p&gt;
&lt;p&gt;They can be expensive. But they also require a fair amount of coding, because you&amp;rsquo;ve got to put in commands that help you get to a state where you can check: Hey, let&amp;rsquo;s turn let&amp;rsquo;s turn the volume of activity up to 200%, to 300%.&lt;/p&gt;
&lt;p&gt;So, some folks do that. but because of the cost and the effort put into it, folks only tend to do this with third party tools when it&amp;rsquo;s &lt;em&gt;really&lt;/em&gt; worth their while, and their management is deeply invested in the idea of having load testing.&lt;/p&gt;
&lt;h3 id="even-then-the-load-testing-needs-to-be-updated-for-some-changes"&gt;Even Then, the Load Testing Needs to Be Updated for Some Changes&lt;/h3&gt;
&lt;p&gt;For some changes, you can test them with load testing tools without any changes. For example, if I refactor a function for performance tuning, but don&amp;rsquo;t change any inputs or outputs, I could test that with an existing configuration of a load testing tool.&lt;/p&gt;
&lt;p&gt;But what if I add a new parameter onto a stored procedure? If I don&amp;rsquo;t change the load testing, will that be appropriate, or not? Should I be running the load test with a variety of values for that?&lt;/p&gt;
&lt;p&gt;Or what if my change involves dropping one procedure and adding in another one? A replay system would have no idea what to do, and with a load testing system I&amp;rsquo;d need to adjust what gets executed, how often, etc.&lt;/p&gt;
&lt;p&gt;When it comes to testing database changes, load testing tools are excellent, but I&amp;rsquo;d expect some human work to be required as well.&lt;/p&gt;
&lt;h2 id="so-most-people-dont-have-automated-performance-and-load-testing-should-that-impact-how-frequently-we-deploy-changes-to-production"&gt;So, Most People Don&amp;rsquo;t Have Automated Performance and Load Testing: Should That Impact How Frequently We Deploy Changes to Production? &lt;/h2&gt;
&lt;p&gt;What we&amp;rsquo;re really looking to find with load testing in the SDLC cycle is regressions in &lt;em&gt;performance&lt;/em&gt;. We should have other testing to catch true defects such as making sure that the right results are returned, etc.&lt;/p&gt;
&lt;p&gt;With database changes, there is a fair amount of work we can do to make sure that things perform well without load testing. There is other due diligence that can help: we can maintain and use a staging or pre-production environment with production size datasets and the same data distribution as production, for example.&lt;/p&gt;
&lt;p&gt;In that environment, we can testing that confirms: what indexes is the modified code using, and are they optimal for the modified code? How long are queries taking? We can make educated guesses about production performance instead of waiting until after a release to see what it&amp;rsquo;s like.&lt;/p&gt;
&lt;p&gt;This level of manual performance testing can work extremely well, and it unlocks us to do frequent deployments, in my experience.&lt;/p&gt;
&lt;h2 id="without-load-testing-its-best-to-frequently-deploy-small-database-changes"&gt;Without Load Testing, It&amp;rsquo;s Best to Frequently Deploy Small Database Changes&lt;/h2&gt;
&lt;p&gt;By small, I mean &lt;em&gt;as small as possible.&lt;/em&gt; A lot of these database changes are going to be things that our customers shouldn&amp;rsquo;t notice at all. Like, hey, we add a new column to this table. We&amp;rsquo;re not actually using it, though. We&amp;rsquo;re going to use it in the future for a feature that&amp;rsquo;s coming out soon.&lt;/p&gt;
&lt;p&gt;But we regularly trickle out the staging steps for a future change. Each of these steps is backwards compatible and deployed well ahead of the point in which we &amp;ldquo;turn on&amp;rdquo; the new feature for our customers, which is often handled via an application control called a feature flag.&lt;/p&gt;
&lt;p&gt;This regular stream of very small changes is helpful for speedily resolving any performance issues which may occur.&lt;/p&gt;
&lt;p&gt;If performance does change, we haven&amp;rsquo;t released a big batch of 50 changes all at once: that&amp;rsquo;s a lot of things to go through to find the culprit. Instead, we&amp;rsquo;ve released maybe 7-10 changes in the last week, and we can look at the most recent ones first, and check if they could be related to the issue.&lt;/p&gt;
&lt;h2 id="what-do-you-mean-by-frequent"&gt;What Do You Mean by &amp;ldquo;Frequent&amp;rdquo;?&lt;/h2&gt;
&lt;p&gt;By &amp;ldquo;frequent&amp;rdquo;, I mean that daily releases shouldn&amp;rsquo;t be a big deal.&lt;/p&gt;
&lt;p&gt;But remember: batch size is critical. This isn&amp;rsquo;t like a race car, this is like a steadily dripping faucet.&lt;/p&gt;
&lt;h2 id="complexity-sometimes-performance-problems-dont-happen-right-after-a-change-is-released"&gt;Complexity: Sometimes Performance Problems Don&amp;rsquo;t Happen Right After a Change Is Released&lt;/h2&gt;
&lt;p&gt;There can be changes that we make where performance is fine for a while, and then something happens. Maybe it&amp;rsquo;s even three weeks after the change was released, but suddenly performance is terrible.&lt;/p&gt;
&lt;p&gt;One particular tricky issue in SQL Server that can cause this is what&amp;rsquo;s called parameter sniffing. If we are using queries that are parameterized, a lot of the way that things perform depends on the execution plan that is cached with the first set of parameters that are passed into the query or procedure when it&amp;rsquo;s compiled, because SQL Server reuses that execution plan until something causes it to recompile.&lt;/p&gt;
&lt;p&gt;Maybe the thing that causes the query to recompile is enough data has changed that statistics automatically update. Maybe it&amp;rsquo;s that there&amp;rsquo;s a failover in an Availability Group. Maybe the SQL Server is restarted. Maybe someone manually clears the execution plan cache.&lt;/p&gt;
&lt;p&gt;A very wide variety of things can change, but if we happen to we have a recompile and we happen to have a compilation with a set of parameters that leads to an execution plan that doesn&amp;rsquo;t work so well, then we can suddenly run into performance issues.&lt;/p&gt;
&lt;p&gt;But this risk of parameter sniffing doesn&amp;rsquo;t mean that we shouldn&amp;rsquo;t release that changes frequently. We&amp;rsquo;re going to have the same risk whether or not we&amp;rsquo;re releasing a big batch of changes or whether we are regularly releasing small changes.&lt;/p&gt;
&lt;p&gt;For issues like this, I like the recent auto-tuning features in SQL Server. Essentially the &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/automatic-tuning/automatic-tuning#automatic-plan-correction"&gt;automatic plan correction feature&lt;/a&gt; will look cases where a query is sometimes fast and sometimes slow, and attempt to identify &amp;ldquo;bad&amp;rdquo; execution plans which are periodically cached for a query.&lt;/p&gt;
&lt;p&gt;You have to have the built-in Query Store feature enabled, and when using on-prem SQL Server this feature requires Enterprise Edition for production (Developer Edition has all the features of Enterprise for non-production environments). But if you do have a SQL Server where performance is critical, this feature is a huge deal. It gives you the option to either let it temporarily correct the plan for you, or to notify you in a DMV that it&amp;rsquo;s spotted a problem that needs tuning.&lt;/p&gt;
&lt;p&gt;This feature can either work with automated load testing: you can use the feature to spot parameter sniffing problems before deployment, or it can give you early warning of performance problems before your customers start complaining. It also gives you insight into how to reproduce these tricky problems outside of production.&lt;/p&gt;
&lt;h2 id="a-quick-recap"&gt;A Quick Recap&lt;/h2&gt;
&lt;p&gt;Automated load testing is fantastic, if you have the time and budget to take it on for your team.&lt;/p&gt;
&lt;p&gt;But if you don&amp;rsquo;t have it, the lack of automated load testing shouldn&amp;rsquo;t block you from frequently deploying small changes to production. By combining targeted manual performance testing into properly planned changes, you can still deploy frequent changes safely into high performance and high uptime environments successfully.&lt;/p&gt;</description></item><item><title>Upcoming Full Day Training: How to Architect Successful Database Changes</title><link>https://kendralittle.com/2019/04/19/upcoming-full-day-training-how-to-architect-successful-database-changes/</link><pubDate>Fri, 19 Apr 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/04/19/upcoming-full-day-training-how-to-architect-successful-database-changes/</guid><description>&lt;p&gt;I&amp;rsquo;m excited to be teaching a full day session with &lt;a href="https://twitter.com/way0utwest"&gt;Steve Jones&lt;/a&gt; at the SQL PASS Summit on Tuesday, November 5, in Seattle.&lt;/p&gt;
&lt;p&gt;Steve and I will be discussing proven patterns to version and deploy changes successfully.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92841"&gt;Read more about this precon session&lt;/a&gt;, or check out the video below where I give a brief overview of what Steve and I will cover.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WIJvcaerblo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="will-you-teach-me-how-to-use-redgate-tools"&gt;Will You Teach Me How to Use Redgate Tools?&lt;/h2&gt;
&lt;p&gt;Nope: not in this session.&lt;/p&gt;
&lt;p&gt;While Steve and I both work for &lt;a href="https://www.red-gate.com/"&gt;Redgate&lt;/a&gt;, we will be showing patterns and approaches that work with both vendor and custom tooling, and we&amp;rsquo;ll do demos with a variety of tools, including free tools when possible. This is &lt;em&gt;absolutely not&lt;/em&gt; a product-specific session, and the patterns discussed have been proven in the industry by developers and DBAs using a wide variety of tooling.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to learn more about Redgate tools, check out the &lt;a href="https://www.pass.org/summit/2019/Learn/SessionDetails.aspx?sid=92888"&gt;Redgate SQL in the City Summit Precon that will be held on Monday, November 4&lt;/a&gt;. That day of training has 100% different content, so if you&amp;rsquo;d like to go all-in on DevOps, join us for both!&lt;/p&gt;
&lt;h2 id="reserve-your-spot"&gt;Reserve Your Spot&lt;/h2&gt;
&lt;p&gt;You can currently &lt;a href="https://www.pass.org/summit/2019/RegisterNow.aspx"&gt;register for an individual pre-conference session for $499, or bundle pre-conference sessions with the conference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope to see you at PASS Summit!&lt;/p&gt;</description></item><item><title>The 2019 State of SQL Server Monitoring Survey Is Open: Here's What's in It for You</title><link>https://kendralittle.com/2019/03/19/the-2019-state-of-sql-server-monitoring-survey-is-open-heres-whats-in-it-for-you/</link><pubDate>Tue, 19 Mar 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/03/19/the-2019-state-of-sql-server-monitoring-survey-is-open-heres-whats-in-it-for-you/</guid><description>&lt;p&gt;Calling all Database Administrators, Developers, Analysts, Consultants, and Managers: Redgate has a survey open asking how you monitor your SQL Servers.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.surveymonkey.com/r/ZZ3G289"&gt;Take the survey before April 5, 2019&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-18-03-2019_19-19-08.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Your time is valuable. The survey will take 5 - 10 minutes to complete. That&amp;rsquo;s not a ton of time, but it&amp;rsquo;s a noticeable part of your day, and there &lt;em&gt;should&lt;/em&gt; be something in it for you. Here&amp;rsquo;s why it&amp;rsquo;s worthwhile to take the survey.&lt;/p&gt;
&lt;h2 id="database-use-patterns-and-monitoring-trends-are-valuable-to-everyone-in-the-community-and-weve-been-missing-out-on-this-trend-information"&gt;Database Use Patterns and Monitoring Trends Are Valuable to Everyone in the Community: and We&amp;rsquo;ve Been Missing Out on This Trend Information!&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t the only survey from Redgate: you may also have heard of the annual &lt;a href="https://www.red-gate.com/solutions/database-devops/report-2019"&gt;State of Database DevOps Report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But this survey is different in important ways: it asks how you manage and monitor your SQL Server database environment, regardless of whether you think about DevOps at all.&lt;/p&gt;
&lt;p&gt;Redgate &lt;a href="https://www.red-gate.com/products/dba/sql-monitor/resources/state-of-sql-server-monitoring"&gt;shared the results of the State of SQL Server Monitoring Survey with readers last year&lt;/a&gt;, and will do so again in 2019. 2018 was the first time we know of that a survey of this kind had been done, and it will be especially interesting to notice what has changed in the past year.&lt;/p&gt;
&lt;h2 id="if-you-fill-out-the-2019-state-of-sql-server-monitoring-survey-youll-get-an-advance-copy-of-the-results-by-email"&gt;If you fill out the 2019 State of SQL Server Monitoring survey, you&amp;rsquo;ll get an advance copy of the results by email&lt;/h2&gt;
&lt;p&gt;The results will help you understand:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What do other DBAs, Developers, and IT Professionals see as their biggest challenges over the coming year?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://www.red-gate.com/products/dba/sql-monitor/resources/state-of-sql-server-monitoring-survey"&gt;last year&amp;rsquo;s report&lt;/a&gt; the biggest challenges were seen as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migrating to the cloud&lt;/li&gt;
&lt;li&gt;How to deploy changes faster to larger environments&lt;/li&gt;
&lt;li&gt;Protecting data – especially for compliance reasons&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m curious to see if these priorities have changed after a year. With GDPR implementation having come to pass and more states and countries around the world passing increasing privacy regulations, I suspect that &amp;lsquo;protecting data&amp;rsquo; may move up from number 3 on the list, but I won&amp;rsquo;t know until we see the data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How much time do your peers spend examining SQL Server health and resolving issues?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is a great question on the survey: and I think this one is absolutely worth some reflection after you take the survey (and after the results come out). Do you spend more time firefighting than you should? If so, what ideas you have to change that?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At what point to most organizations move from manual monitoring to a third party tool?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you work for a growing company and are interested in making the case to purchase monitoring to your management, it may be useful to know information like this&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Respondents with fewer than 10 servers were twice as likely to rely on manual monitoring as to use a paid-for tool. Those with 10 or more servers were more likely to use third-party software.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.red-gate.com/products/dba/sql-monitor/resources/state-of-sql-server-monitoring-survey"&gt;2018 State of SQL Server Monitoring Report&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="survey-results-will-help-you-prioritize-what-to-learn"&gt;Survey Results Will Help You Prioritize What to Learn&lt;/h2&gt;
&lt;p&gt;Are you curious as to whether you should learn another database platform, such as MongoDB, Oracle, MySQL, Cosmos DB, or PostGres? The survey will show how much respondents report that they are using each platform, and whether they think the amount will increase or decrease.&lt;/p&gt;
&lt;p&gt;Want to know whether you should invest time (and maybe ask for some budget) to explore cloud technologies like Azure Managed Instances, Azure SQL Database, or Amazon RDS? The survey will show how many of your peers are using each one.&lt;/p&gt;
&lt;h2 id="also-you-could-win-money"&gt;Also, You Could Win Money&lt;/h2&gt;
&lt;p&gt;Everyone who completes the survey and provides their details at the end will be entered into a prize draw to win a $250 Amazon Voucher (or equivalent in your local currency).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.surveymonkey.com/r/ZZ3G289"&gt;Take the 2019 State of SQL Server Monitoring Survey&lt;/a&gt;&lt;/p&gt;</description></item><item><title>The SQL Server Data Row Size Question: Why Is It Bigger?</title><link>https://kendralittle.com/2019/03/19/the-sql-server-data-row-size-question-why-is-it-bigger/</link><pubDate>Tue, 19 Mar 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/03/19/the-sql-server-data-row-size-question-why-is-it-bigger/</guid><description>&lt;p&gt;This morning, I received the following question from a user:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Could you please clarify SQLServer &amp;ldquo;Data Row&amp;rdquo; size:
If I run the script below on SQL Server 2012, then Slot(row) Size is 710 bytes
if I run the same script against SQL Server 2016 and above, then Slot(row) Size is 724 bytes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They then provided a script which creates and inserts a few rows into a sample table, runs the DBCC IND command to find a list of pages for the sample table, then uses the DBCC PAGE command to examine the page.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Row-Size-Corgi-Ruler.jpg"
alt="Illustration of a corgi with a ruler, representing row size measurement" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="the-first-thing-i-looked-for-how-many-bytes-is-the-difference-is-it-14-bytes"&gt;The First Thing I Looked For: How Many Bytes Is the Difference? Is It 14 Bytes?&lt;/h2&gt;
&lt;p&gt;I love it when someone sends me a repro script, but in this case I didn&amp;rsquo;t need to run it. The first thing I did was to look at the two numbers given for row size, and to subtract the smaller one from the larger one: 724 - 710 = 14 bytes of difference.&lt;/p&gt;
&lt;p&gt;That bit of information alone gave me an immediate guess of what was going on.&lt;/p&gt;
&lt;h2 id="row-versioning-in-sql-server-has-a-14-byte-row-overhead"&gt;Row Versioning in SQL Server Has a 14-Byte Row Overhead&lt;/h2&gt;
&lt;p&gt;You can reduce blocking in SQL Server by enabling &amp;ldquo;optimistic&amp;rdquo; locking. There are trade-offs for this approach, however: row versions are enabled in tempdb, and 14 bytes of overhead may be required on impacted rows. (For a quick overview of this row versioning process, check out this &lt;a href="https://www.red-gate.com/simple-talk/sql/t-sql-programming/row-versioning-concurrency-in-sql-server/"&gt;Simple Talk post by Kalen Delaney&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;My guess is that row versioning is enabled only on the SQL Server 2016 and above instances that are being tested in this case. This could be because of &lt;em&gt;any&lt;/em&gt; of the following&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Snapshot isolation is allowed on the database&lt;/li&gt;
&lt;li&gt;Read committed snapshot isolation is enabled on the database&lt;/li&gt;
&lt;li&gt;The database has a readable secondary in an availability group&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="you-might-wonder-why-would-having-a-readable-secondary-cause-the-row-to-grow"&gt;You Might Wonder: Why Would Having a Readable Secondary Cause the Row to Grow?&lt;/h2&gt;
&lt;p&gt;Readable secondaries in SQL Server allow you to offload read workloads.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s important to minimize blocking against those readable secondaries, though: you don&amp;rsquo;t want data modifications flowing through to the readable secondary to be blocked by reporting queries that you are running against the secondary, after all. You also want reads to be as consistent as possible.&lt;/p&gt;
&lt;p&gt;For this reason, queries that are run against readable secondaries are automatically escalated to snapshot isolation. And snapshot isolation requires row versioning &amp;ndash; those 14 bytes of space are needed too help make it all work.&lt;/p&gt;
&lt;p&gt;But readable secondaries are &lt;em&gt;read-only&lt;/em&gt;, right? So how can it write those 14 bytes? The answer is that it&amp;rsquo;s complicated. Here&amp;rsquo;s the documentation from in the &amp;ldquo;capacity planning&amp;rdquo; concerns in Microsoft&amp;rsquo;s docs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When you configure read-access for one or more secondary replicas, the primary databases add 14 bytes of overhead on deleted, modified, or inserted data rows to store pointers to row versions on the secondary databases for disk-based tables. This 14-byte overhead is carried over to the secondary databases. As the 14-byte overhead is added to data rows, page splits might occur.&lt;/p&gt;
&lt;p&gt;The row version data is not generated by the primary databases. Instead, the secondary databases generate the row versions. However, row versioning increases data storage in both the primary and secondary databases.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/database-engine/availability-groups/windows/active-secondaries-readable-secondary-replicas-always-on-availability-groups#bkmk_CapacityPlanning"&gt;Offload read-only workload to secondary replica of an Always On availability group&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To dig into the details of this more, click the link &amp;ndash; there&amp;rsquo;s even more info on the full page.&lt;/p&gt;</description></item><item><title>Why You Shouldn't Hardcode the Current Database Name in Your Views, Functions, and Stored Procedures</title><link>https://kendralittle.com/2019/03/18/why-you-shouldnt-hardcode-the-current-database-name-in-your-views-functions-and-stored-procedures/</link><pubDate>Mon, 18 Mar 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/03/18/why-you-shouldnt-hardcode-the-current-database-name-in-your-views-functions-and-stored-procedures/</guid><description>&lt;p&gt;I recently published &lt;a href="https://www.red-gate.com/simple-talk/opinion/editorials/why-you-shouldnt-hardcode-the-current-database-name-in-your-views-functions-and-stored-procedures/?utm_source=dlvr.it&amp;amp;utm_medium=twitter"&gt;Why You Shouldn&amp;rsquo;t Hardcode the Current Database Name in Your Views, Functions, and Stored Procedures&lt;/a&gt; over on Simple Talk.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-11-03-2019_22-46-32.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="what-the-article-covers"&gt;What the Article Covers&lt;/h2&gt;
&lt;p&gt;In the article, I discuss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why referencing the current database name creates a dependency&lt;/li&gt;
&lt;li&gt;What &amp;lsquo;deferred name resolution&amp;rsquo; is, and why the dependency may be more noticeable in views and some functions (rather than stored procedures)&lt;/li&gt;
&lt;li&gt;Which activities are most likely to break if you place dependencies on the current database name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.red-gate.com/simple-talk/opinion/editorials/why-you-shouldnt-hardcode-the-current-database-name-in-your-views-functions-and-stored-procedures/?utm_source=dlvr.it&amp;amp;utm_medium=twitter"&gt;Read the full article here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>PASS Summit 2019 Call for Speakers Is Open: How I Sketch Out My Submission Ideas</title><link>https://kendralittle.com/2019/03/13/pass-summit-2019-call-for-speakers-is-open-how-i-sketch-out-my-submission-ideas/</link><pubDate>Wed, 13 Mar 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/03/13/pass-summit-2019-call-for-speakers-is-open-how-i-sketch-out-my-submission-ideas/</guid><description>&lt;p&gt;Are you interested in speaking at the Professional Association for SQL Server&amp;rsquo;s &lt;a href="https://www.pass.org/summit/2019/Home.aspx"&gt;annual Summit conference&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;The call for speakers is now open, and you may &lt;a href="https://www.pass.org/summit/2019/Speakers/Callforspeakers.aspx?utm_source=cnctr&amp;amp;utm_medium=email&amp;amp;utm_campaign=Summit_CFS_2019&amp;amp;mkt_tok=eyJpIjoiWXprMVlUa3pNamRqWVRCaSIsInQiOiJ1RUF2V1owZlRKbmNVK2FSRzdJNjUyMXZOZ3A5TTBcLzk4OGR6aFh6bTQyejc0MUVTWlFLbzNicGFRbm5VNHNKWkU4NmprV0Roa3hWbGlVZHFyQnVYWGNhRTZNYzNndG43WVZQSHVLXC83VU50aDUzRTRMRGpSeXlVTDJWbHhrempwIn0%3D"&gt;submit up to three sessions between now and March 31, 2019&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sketching out my ideas for what sessions that I&amp;rsquo;d like to submit, and I thought I&amp;rsquo;d share my process here.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-11-03-2019_19-00-32.jpg"
alt="Illustration about session planning and submission ideas" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="generating-ideas-what-am-i-interested-in-spending-six-months-thinking-about"&gt;Generating Ideas: What Am I Interested in Spending Six Months Thinking About?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m a bit selfish when it comes to topic selection, and I think that&amp;rsquo;s fine: it needs to be something that I&amp;rsquo;m interested in thinking about for more than half a year.&lt;/p&gt;
&lt;p&gt;That does NOT mean that it needs to be super-advanced rocket science content. Figuring out how to present introductory level content clearly, in an easy-to-understand way takes a lot of time. The topic simply needs to compelling enough for me to stay interested.&lt;/p&gt;
&lt;h2 id="a-filter-is-the-topic-relevant-to-enough-people"&gt;A Filter: Is the Topic Relevant to Enough People?&lt;/h2&gt;
&lt;p&gt;When I first began speaking, I thought I needed to speak on topics that were unique to me, which other people in the community didn&amp;rsquo;t already &amp;ldquo;have covered.&amp;rdquo; This led me to somewhat esoteric concepts. There&amp;rsquo;s a big downside to that: your talks simply won&amp;rsquo;t be relevant to many people.&lt;/p&gt;
&lt;p&gt;Now, I encourage myself (and you) to use the opposite filter: think about talks that will be be helpful to a &lt;em&gt;lot&lt;/em&gt; of people. That means you probably won&amp;rsquo;t be the first one in the world to deliver a talk on the topic, and that&amp;rsquo;s perfectly fine: your perspective is valuable!&lt;/p&gt;
&lt;p&gt;There is definitely a &amp;ldquo;three bears&amp;rdquo; aspect to this filter. Your talk doesn&amp;rsquo;t need to be useful to everyone at the event. But do think about your intended audience, and whether you&amp;rsquo;ll help a significant portion of the audience at the event.&lt;/p&gt;
&lt;h2 id="sketching-out-ideas-and-audiences"&gt;Sketching Out Ideas and Audiences&lt;/h2&gt;
&lt;p&gt;For this year&amp;rsquo;s PASS Summit talks, I currently have two topics I&amp;rsquo;m quite passionate about, which I&amp;rsquo;d love to share.&lt;/p&gt;
&lt;p&gt;Right now I don&amp;rsquo;t have abstracts. I&amp;rsquo;ve started by creating notes on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subject matter area / rough title&lt;/li&gt;
&lt;li&gt;What the talk would include - a problem summary (which I write as quickly as possible, just throwing out ideas) and a bulleted list of content ideas&lt;/li&gt;
&lt;li&gt;Who would care (audience) and why they would care&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s where I&amp;rsquo;m at with my two topics.&lt;/p&gt;
&lt;h2 id="topic-1-source-controlling-index-code-in-a-changing-world"&gt;Topic 1: Source Controlling Index Code in a Changing World &lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alternate title&lt;/strong&gt;: I prefer, &amp;ldquo;How to Standardize Index Code in a Changing World.&amp;rdquo; Not everyone may get that Standardize = Source Control, however &amp;ndash; not sure if that&amp;rsquo;s simply how I think of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem summary&lt;/strong&gt;: It&amp;rsquo;s critical to get database code standardized into source control to manage collaboration, store and version your organization&amp;rsquo;s intellectual property, and to track and audit what has happened in your database code. The database code for indexes, however, is increasingly difficult to standardize: new features in Azure SQL DB automate the process of tuning index schema. Single-tenant database architectures often standardize table schemas, but require customizations of indexes for performance in individual databases. And index schema often needs to &amp;ldquo;drift&amp;rdquo; in production as operations teams respond to critical performance problems. How do you adapt successfully to this chaos, yet still maintain your sanity by managing your database code in source control?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Topics to include:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Differences in source controlling indexes with state vs migrations approaches to database code
&lt;ul&gt;
&lt;li&gt;Strategies for working around limitations on advanced index features with a state approach&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How to manage drift that occurs with automatic indexing in Azure SQL Database&lt;/li&gt;
&lt;li&gt;How to manage incidents where indexes are manually changed/drifted in production due to a critical need without going through a full release cycle &lt;/li&gt;
&lt;li&gt;How to manage single-tenant environments where the indexes are customized in individual databases &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Audience / who would care:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developers and DBAs who have their databases in source control, but who struggle with &amp;ldquo;drift&amp;rdquo; in some areas&lt;/li&gt;
&lt;li&gt;Developers and DBAs interested in getting databases into source control &amp;ndash; sometimes thinking ahead about these more advanced issues at the beginning can help you learn fast&lt;/li&gt;
&lt;li&gt;Architects thinking about using single-tenant designs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="topic-2-best-practices-for-branching-database-code-in-git"&gt;Topic 2: Best Practices for Branching Database Code in Git &lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Problem summary:&lt;/strong&gt; There are quite a few discussions and patterns available online for branching application code, but special considerations apply when it comes to database code &amp;ndash; and hardly anyone has written about this! This talk helps DBAs and developers design the simplest branching strategy that meets the needs of their organization. I will share key considerations for designing a branching strategy for database code, and we will discuss multiple popular branching models along with &amp;ldquo;fit notes&amp;rdquo; describing the strengths and weaknesses of each model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Topics to include:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The overarching rule of “keep it simple”, but why this leads to different practices for small teams (1-2 devs checking in code) vs larger teams&lt;/li&gt;
&lt;li&gt;State-first vs migrations-first and explain what that means for branching - a migrations approach that &lt;em&gt;doesn’t&lt;/em&gt; include a state component will SUCK for merging &amp;hellip; maybe don&amp;rsquo;t use the word SUCK in all caps in the final abstract tho&lt;/li&gt;
&lt;li&gt;Why shared vs dedicated development databases is important when considering branching - why object locking is a necessarily evil of a shared model, so don’t do shared if you can avoid it (esp considering that Dev Edition is free for SQL Server, side-eye at Oracle)&lt;/li&gt;
&lt;li&gt;What feature branches are and how to tell if you need them &lt;/li&gt;
&lt;li&gt;What release branches are and how to tell if you need them &lt;/li&gt;
&lt;li&gt;Pull requests &lt;/li&gt;
&lt;li&gt;Rebasing &lt;/li&gt;
&lt;li&gt;Branching diagrams for multiple popular models, and &amp;ldquo;fit notes&amp;rdquo; for the teams using them&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Audience / who would care:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Me!!! Hahahaha, I find this topic fascinating, even if there were five people in the room I&amp;rsquo;d be thrilled (but I do think this would be quite popular with dev-minded folks, I don&amp;rsquo;t think it&amp;rsquo;s just me)&lt;/li&gt;
&lt;li&gt;Developers and DBAs who want to get database code into source control&lt;/li&gt;
&lt;li&gt;Developers and DBAs who have code in source control, and who struggle with:
&lt;ul&gt;
&lt;li&gt;Managing concurrent changes to objects&lt;/li&gt;
&lt;li&gt;Building the codebase from scratch to a specific release / version&lt;/li&gt;
&lt;li&gt;Managing drift in different environments / comparing database versions to source versions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next-steps-mulling-these-over"&gt;Next Steps: Mulling These Over&lt;/h2&gt;
&lt;p&gt;I feel pretty good about these topics so far: I think that I care enough about them to want to spend a good amount of time with them, and I think that enough people at the conference care about the problems discussed to make them worthwhile.&lt;/p&gt;
&lt;p&gt;These two talks are a bit more focused than talks I&amp;rsquo;ve done in the past, in that they&amp;rsquo;re specific to managing code in source control. I&amp;rsquo;m strongly of the opinion that &lt;em&gt;everyone&lt;/em&gt; should be managing their database code in source control, though, so I&amp;rsquo;m fine with the level of focus &amp;ndash; source control should be the norm!&lt;/p&gt;
&lt;p&gt;I am presently waiting a few days before writing and revising &amp;ldquo;real&amp;rdquo; abstracts. I&amp;rsquo;ve got some time before the deadline, and I find it&amp;rsquo;s good that I sit with a topic for a few days to see if a bright new idea occurs to me, or to see if I may want to go in a different direction.&lt;/p&gt;
&lt;h2 id="first-time-speaker-go-ahead-and-submit"&gt;First Time Speaker? Go Ahead and Submit!&lt;/h2&gt;
&lt;p&gt;Writing an abstract and choosing a title for a talk can be daunting. I personally find it easier to start with making notes about a potential talk like I&amp;rsquo;ve shown here, and then refining those notes. I am hoping that helps some potential speakers out there to get started.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pass.org/summit/2019/Speakers/Callforspeakers.aspx?utm_source=cnctr&amp;amp;utm_medium=email&amp;amp;utm_campaign=Summit_CFS_2019&amp;amp;mkt_tok=eyJpIjoiWXprMVlUa3pNamRqWVRCaSIsInQiOiJ1RUF2V1owZlRKbmNVK2FSRzdJNjUyMXZOZ3A5TTBcLzk4OGR6aFh6bTQyejc0MUVTWlFLbzNicGFRbm5VNHNKWkU4NmprV0Roa3hWbGlVZHFyQnVYWGNhRTZNYzNndG43WVZQSHVLXC83VU50aDUzRTRMRGpSeXlVTDJWbHhrempwIn0%3D"&gt;Here&amp;rsquo;s that link to the call of speakers again &amp;ndash; submit by March 31, 2019&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Contest: Tell Your Database Development Disaster Story (5 Winners Get $150 USD or More Each)</title><link>https://kendralittle.com/2019/03/12/contest-tell-your-database-development-disaster-story-5-winners-get-150-usd-or-more-each/</link><pubDate>Tue, 12 Mar 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/03/12/contest-tell-your-database-development-disaster-story-5-winners-get-150-usd-or-more-each/</guid><description>&lt;p&gt;Redgate is building a library of real-world stories about database development disasters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your mission:&lt;/strong&gt; Tell us a true story in 500 words or less about a time when you were involved in an Agile or DevOps project that went full steam ahead in speeding up delivery of application code, but didn’t modernize database development practices. Did trouble follow? &lt;a href="https://www.red-gate.com/hub/entrypage/competition"&gt;Check out the prizes and give us the scoop here&lt;/a&gt; &lt;strong&gt;before March 20, 2019&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-11-03-2019_20-59-29.jpg"
alt="Promotional image for the database development disaster story contest"&gt;
&lt;/figure&gt;
&lt;h2 id="enter-today-times-almost-up"&gt;Enter Today, Time&amp;rsquo;s Almost Up!&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.red-gate.com/hub/entrypage/competition"&gt;Share your story using the form here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The story must be true – but never fear, we will anonymize all stories and the names of the winners&lt;/li&gt;
&lt;li&gt;Enter as often as you’d like (but each person may only win once)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="need-inspiration"&gt;Need Inspiration?&lt;/h2&gt;
&lt;h2 id="grants-sample-entry-the-short-version"&gt;Grant&amp;rsquo;s Sample Entry (The Short Version)&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Our organization built a new application using an Object Relational Mapping (ORM) tool. The team worked without any DBAs or database developers for speed. We ended up with an incredibly slow application that nobody could report from at the end – and deployments dropped and recreated tables! We had to implement weird workarounds to make deployments safe. The project delivered late and required a lot of unexpected budget from consultants. If our teams had been able to work together on the database as part of the project, we would have saved the company a lot of time and money.&amp;rdquo; &amp;hellip;&lt;a href="https://www.red-gate.com/simple-talk/sql/database-devops-sql/devops-without-the-database-a-cautionary-tale/"&gt;Read Grant&amp;rsquo;s full article&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="my-development-disaster-story-the-v1-teams-doomed-redesign"&gt;My Development Disaster Story: The V1 Team&amp;rsquo;s Doomed Redesign&lt;/h2&gt;
&lt;p&gt;Once upon a time, I worked for a startup which purchased another startup. For the first year, the acquired company&amp;rsquo;s applications operated independently, as they were originally designed. After that point, developers from both organizations began merging together, and a team was created and assigned the task of redesigning the applications of the purchased company to be more scalable. Let&amp;rsquo;s call this the &amp;ldquo;V1 Team.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The existing production legacy applications involved complex data processing. The idea was that the V1 Team would reproduce almost all functionality of the legacy applications in the initial release of the redone application.&lt;/p&gt;
&lt;p&gt;The V1 Team went off and began work. As they worked through their long development cycle, features continued to be added to the production application. These were added to the workload of the V1 Team, continuously increasing the scope of their project and delaying their initial release date.&lt;/p&gt;
&lt;p&gt;There were a lot of quite smart developers on the V1 Team, people I enjoyed working with, but I found myself stopping by their area less frequently over time - frankly, it was a depressing place to visit. The team was overworked and frustrated. They were never releasing any code to production, and there were no design meetings with anyone.&lt;/p&gt;
&lt;p&gt;Finally, we heard that the redesigned applications were going to be ready to launch soon! This was good news, as the legacy applications were not easy to support.&lt;/p&gt;
&lt;p&gt;The first thing I remember about the database deployments for the V1 Team&amp;rsquo;s new application is that… well, they didn&amp;rsquo;t actually deploy. The V1 Team had been stuck in a prototype environment for so long that quite a bit of work was needed to bring the codebase into a deployable state for pre-production and production domains.&lt;/p&gt;
&lt;p&gt;The second thing I remember is looking at one example table in one of the V1 Team&amp;rsquo;s new databases, and finding that the clustered primary key was defined as being the combination of four uniqueidentifier columns (GUIDs).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not the kind of DBA who sees a uniqueidentifier column as being universally bad or a sign of doom. However, keeping clustering keys relatively narrow is generally a good practice for scalability in SQL Server: and a 64 byte surrogate key is a particularly bad sign. And it was too late to make any changes: the poor V1 Team was desperate to get anything in front of a customer at this point.&lt;/p&gt;
&lt;p&gt;It was a tricky and painful struggle for both the V1 Team and the operations teams to get that code into production and to begin supporting it. Performance wasn&amp;rsquo;t great, and customer response was lukewarm at best: after all, they&amp;rsquo;d been told the whole project was about scalability.&lt;/p&gt;
&lt;p&gt;Nobody declared victory, least of all the customers.&lt;/p&gt;
&lt;p&gt;Scoping and architecture discussions, I learned, are critical for any project.&lt;/p&gt;</description></item><item><title>Kendra Breaks and Fixes SQL Source Control in 9 Minutes</title><link>https://kendralittle.com/2019/03/04/watch-kendra-breaks-and-fixes-sql-source-control-9-minutes/</link><pubDate>Mon, 04 Mar 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/03/04/watch-kendra-breaks-and-fixes-sql-source-control-9-minutes/</guid><description>&lt;p&gt;I love breaking technology.&lt;/p&gt;
&lt;p&gt;I love breaking technology &lt;strong&gt;on purpose&lt;/strong&gt;, in a place where it&amp;rsquo;s not going to slow anyone else down. It&amp;rsquo;s a great way to learn more about how everything works and what your options are to fix the situation when things go sideways.&lt;/p&gt;
&lt;h2 id="the-video"&gt;The Video&lt;/h2&gt;
&lt;p&gt;In this 9 minute video, I ignore SQL Source Control&amp;rsquo;s valiant attempts to keep me out of trouble, and put the database code in my local git repository into an inconsistent state. Can I fix it?&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/psiss9iZJzM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>New Free Videos on SQL Prompt, SQL Compare, and SQL Doc with Redgate SQL Change Automation</title><link>https://kendralittle.com/2019/02/15/new-free-videos-on-sql-prompt-sql-compare-and-sql-doc-with-redgates-sql-change-automation/</link><pubDate>Fri, 15 Feb 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/02/15/new-free-videos-on-sql-prompt-sql-compare-and-sql-doc-with-redgates-sql-change-automation/</guid><description>&lt;p&gt;I&amp;rsquo;m excited to have just clicked &amp;lsquo;publish&amp;rsquo; on four new videos in the brand new &lt;a href="https://www.youtube.com/playlist?list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc"&gt;Advocate playlist on Redgate&amp;rsquo;s YouTube channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These videos step through setting up and working with a project in one of my favorite Redgate tools: &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/index"&gt;SQL Change Automation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-04-03-2019_16-12-47.jpg" width="230"&gt;
&lt;/figure&gt;
SQL Change Automation is that it gives you two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fine-grained control to tune and order the execution of changes to your database with a migrations-first approach to source controlling your code&lt;/li&gt;
&lt;li&gt;A view of the state of your database, which is crucial for code reviews, controlling environment drift, and communicating about changes between developers and database administrators&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-tricky-bit"&gt;The Tricky Bit&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a lot to learn when starting out with SQL Change Automation if you haven&amp;rsquo;t used a migrations-first approach in the past, or aren&amp;rsquo;t used to working in Visual Studio.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s where these videos come in: you can follow along with the demos in your own installation of Visual Studio and Redgate&amp;rsquo;s SQL Toolbelt, or just watch and learn. I take it slow and don&amp;rsquo;t assume that you&amp;rsquo;re an expert in Visual Studio.&lt;/p&gt;
&lt;h2 id="in-one-hour-of-demos-you-will-learn"&gt;In One Hour of Demos, You Will Learn&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;How to set up a SQL Change Automation project with Microsoft&amp;rsquo;s Northwind sample database&lt;/li&gt;
&lt;li&gt;What a baseline is and how to create one&lt;/li&gt;
&lt;li&gt;What programmable objects are, and how to edit one offline in Visual Studio&lt;/li&gt;
&lt;li&gt;What the offline schema model is, and how to work with it in Visual Studio&lt;/li&gt;
&lt;li&gt;How to use branches and SQLCompare with SQL Change Automation projects&lt;/li&gt;
&lt;li&gt;How to automate the production of database documentation with the SQL Change Automation PowerShell cmdlets&lt;/li&gt;
&lt;li&gt;How to build and deploy with SQL Change Automation PowerShell cmdlets&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-arent-you-working-in-ssms-in-the-videos"&gt;Why Aren&amp;rsquo;t You Working in SSMS in the Videos?&lt;/h2&gt;
&lt;p&gt;If you prefer working in SQL Server Management Studio or Azure Data Studio, you can choose to make database changes there, then import the changes into SQL Change Automation as scripts that you tweak as desired in Visual Studio. That&amp;rsquo;s a valid workflow, and I often use it myself.&lt;/p&gt;
&lt;p&gt;In these videos I show how to do all the work in Visual Studio &amp;ndash; because although I&amp;rsquo;m a long time SSMS fan, it&amp;rsquo;s pretty convenient to know how to do your work in multiple tools.&lt;/p&gt;
&lt;h2 id="tools-used-in-the-videos"&gt;Tools Used in the Videos&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://visualstudio.microsoft.com/downloads/"&gt;Microsoft Visual Studio 2017&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.red-gate.com/products/sql-development/sql-toolbelt/index"&gt;Redgate SQL Toolbelt&lt;/a&gt; - Free Trial available&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/"&gt;VSCode&lt;/a&gt; - I use this for PowerShell script execution - you could use the PowerShell ISE instead, or just execute scripts from the command line&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="using-sql-toolbelt-components-with-sql-change-automation-create-your-demo-environment"&gt;Using SQL Toolbelt Components with SQL Change Automation: Create Your Demo Environment&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/4at2X4qz4MM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;This is the first of four videos on using SQL Toolbelt components (SQL Prompt, SQL Compare, and SQL Doc) with SQL Change Automation Projects. Follow along to set up the demo environment used in the next three videos.&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=4at2X4qz4MM&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=1&amp;amp;t=67s"&gt;1:07&lt;/a&gt; - Download the Northwind Sample Database script from Microsoft: &lt;a href="https://www.youtube.com/redirect?v=4at2X4qz4MM&amp;amp;redir_token=AgAvEsgFkGTD6gUZ3EAFq8Mrnot8MTU1MDI1OTE3MUAxNTUwMTcyNzcx&amp;amp;event=video_description&amp;amp;q=http%3A%2F%2Fbit.ly%2Fmsftnorthwind"&gt;http://bit.ly/msftnorthwind&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=4at2X4qz4MM&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=1&amp;amp;t=135s"&gt;2:15&lt;/a&gt; - Create the Northwind Database and the empty NorthwindDev database from Visual Studio&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=4at2X4qz4MM&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=1&amp;amp;t=260s"&gt;4:20&lt;/a&gt; - Create the SQL Change Automation project and create a baseline script&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=4at2X4qz4MM&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=1&amp;amp;t=510s"&gt;8:30&lt;/a&gt; - View pending deploy of the project to the NorthwindDev database&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=4at2X4qz4MM&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=1&amp;amp;t=533s"&gt;8:53&lt;/a&gt; - View location of baseline script, programmable objects, and offline schema model in Solution Explorer. Check for &amp;lsquo;Unsupported&amp;rsquo; folder.&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=4at2X4qz4MM&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=1&amp;amp;t=604s"&gt;10:04&lt;/a&gt; - Deploy to the NorthwindDev database&lt;/p&gt;
&lt;h2 id="using-sql-prompt-with-sql-change-automation-in-visual-studio"&gt;Using SQL Prompt with SQL Change Automation in Visual Studio&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/x3Ro7-Nd4I4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Learn how SQL Prompt can help you quickly improve TSQL scripts in Visual Studio with SQL Change Automation.&lt;br&gt;
The PowerShell script shown is available at: &lt;a href="https://www.youtube.com/redirect?v=x3Ro7-Nd4I4&amp;amp;redir_token=0ebzH9z77iSTeb-nt2lUMvk4NkR8MTU1MDI1OTEzMkAxNTUwMTcyNzMy&amp;amp;event=video_description&amp;amp;q=http%3A%2F%2Fbit.ly%2F2IfgmUK"&gt;http://bit.ly/2IfgmUK&lt;/a&gt;&lt;br&gt;
In this video:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;index=2&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;t=20s"&gt;00:20&lt;/a&gt; - Overview of programmable objects in SQL Change Automation&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;index=2&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;t=75s"&gt;01:15&lt;/a&gt; - Overview of the offline schema model in SQL Change Automation &lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=2&amp;amp;t=130s"&gt;2:10&lt;/a&gt; - Demo of refactoring a stored procedure (a programmable object) begins&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=2&amp;amp;t=450s"&gt;7:30&lt;/a&gt; - Saving the &amp;ldquo;offline edit&amp;rdquo; to the programmable object triggers option to deploy to development database&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=2&amp;amp;t=548s"&gt;9:08&lt;/a&gt; - Test full build and deploy of first committed change in VS Code with PowerShell components&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;index=2&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;t=795s"&gt;13:15&lt;/a&gt; - Demo of editing an index on a table with SQL Server Data tools and generating a migration script begins. This demo shows the &amp;ldquo;offline schema model&amp;rdquo;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=2&amp;amp;t=1219s"&gt;20:19&lt;/a&gt; - Deploy the edited migration script&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;index=2&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;t=1360s"&gt;22:40&lt;/a&gt; - Perform build and deploy with PowerShell cmdlets&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=x3Ro7-Nd4I4&amp;amp;index=2&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;t=1440s"&gt;24:00&lt;/a&gt; - Review release artifact&lt;/p&gt;
&lt;h2 id="using-sql-compare-with-sql-change-automation"&gt;Using SQL Compare with SQL Change Automation&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Bv2rb_ORZnc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Learn how you can use SQL Compare with SQL Change Automation projects in Visual Studio to compare database state at different points in your project.&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;t=16s&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3"&gt;00:16&lt;/a&gt; - How the SQL Compare is used by SQL Change Automation under the hood&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3&amp;amp;t=63s"&gt;1:03&lt;/a&gt; - Demo begins with a view of the Northwind SQL Change Automation Project in Visual Studio&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3&amp;amp;t=110s"&gt;1:50&lt;/a&gt; - Demo of setting up the source and target in SQL Compare, with discussion of how this comparison uses programmable objects and the offline schema model&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;t=263s&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3"&gt;4:23&lt;/a&gt; - View of the results of the comparison&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3&amp;amp;t=306s"&gt;5:06&lt;/a&gt; - Demo of creating and checking out a branch in Git via Visual Studio &lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;t=397s&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3"&gt;6:37&lt;/a&gt; - Demo of refreshing SQL Compare after the branch switch in Visual Studio, and how and why the results change&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Bv2rb_ORZnc&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=3&amp;amp;t=473s"&gt;7:53&lt;/a&gt; - Demo of switching back to the master branch and a few of how this once again changes the comparison being performed (in a good way)&lt;/p&gt;
&lt;h2 id="automating-sql-doc-with-sql-change-automation"&gt;Automating SQL Doc with SQL Change Automation&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/xRjmWKe7MgQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Learn how to automate the production of database documentation using the SQL Change Automation PowerShell cmdlets to produce SQL Doc documentation.&lt;br&gt;
The PowerShell script shown is available at: &lt;a href="https://www.youtube.com/redirect?q=http%3A%2F%2Fbit.ly%2F2V14Lui&amp;amp;event=video_description&amp;amp;redir_token=_Fxx2Ry8Emww3igK_QCByxTaIbh8MTU1MDI1OTk2NUAxNTUwMTczNTY1&amp;amp;v=xRjmWKe7MgQ"&gt;http://bit.ly/2V14Lui&lt;/a&gt;&lt;br&gt;
In this video:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=xRjmWKe7MgQ&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=4&amp;amp;t=66s"&gt;1:06&lt;/a&gt; - Start of demo in VSCode, walk through of some key points of the script&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=xRjmWKe7MgQ&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=4&amp;amp;t=208s"&gt;3:28&lt;/a&gt; - Explanation of why I am specifying a SQL Server instance for the documentation and not using LocalDB&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=xRjmWKe7MgQ&amp;amp;list=PLhFdCK734P8B6c78JliKyv2U0StNC0Skc&amp;amp;index=4&amp;amp;t=225s"&gt;3:45&lt;/a&gt; - View of the resulting documentation in a .zip output file begins&lt;/p&gt;</description></item><item><title>What a Software Evangelist Does and Where the Job Is Going (Dear SQL DBA Episode 67)</title><link>https://kendralittle.com/2019/01/29/what-a-software-evangelist-does-and-where-the-job-is-going-dear-sql-dba-episode-67/</link><pubDate>Tue, 29 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/29/what-a-software-evangelist-does-and-where-the-job-is-going-dear-sql-dba-episode-67/</guid><description>&lt;p&gt;I&amp;rsquo;ve been working as an Evangelist at Redgate for close to six months now, and one question keeps coming up: what exactly does an Evangelist do at a software company? In 21 minutes, I explain the core mission of Evangelists, and why I think being part of the sales process is an important part of the future of software evangelism.&lt;/p&gt;
&lt;p&gt;A transcript is below the video if you&amp;rsquo;d rather read. You can also &lt;a href="https://dearsqldba.libsyn.com/site/"&gt;subscribe to the podcast to listen on the go&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/ksTpbSAgCZc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="episode-transcript"&gt;Episode Transcript&lt;/h2&gt;
&lt;p&gt;Hello and welcome to Dear SQL DBA, a podcast, YouTube show, and now a twitch stream for database developers and database administrators.&lt;/p&gt;
&lt;p&gt;I am Kendra Little from Redgate Software and from SQLWorkbooks. Today I want to chat about what it is evangelists do. My job at Redgate: my job title is that I&amp;rsquo;m an Evangelist. I&amp;rsquo;ve gotten the question from multiple folks, including people at passport control, as to what exactly is it that you do as an evangelist? Because it really really isn&amp;rsquo;t always obvious, and I think it&amp;rsquo;s changing as well. I think the role of Evangelists who&amp;rsquo;ve been around in software companies for a while is evolving.&lt;/p&gt;
&lt;h2 id="how-i-first-encountered-an-evangelist-a-man-yelling-into-a-phone"&gt;How I First Encountered an &amp;lsquo;Evangelist&amp;rsquo;: A Man Yelling into a Phone&lt;/h2&gt;
&lt;p&gt;I first heard of this job title way back when I first was working at Microsoft. I think I was still a contractor there. I got a job at Microsoft as a contractor, and I was very very excited to be working at Microsoft. It was an amazing job. I worked a lot and I learned a ton: of course I was an hourly employee so working a lot was actually to my benefit. I eventually did become a full-time employee at Microsoft and kept learning more and more there as well, and it was great. But at this time, I was still a contractor.&lt;/p&gt;
&lt;p&gt;The first encounter I had with an evangelist was&amp;hellip; we were in these buildings where everyone was in offices. They weren&amp;rsquo;t cube farms at all. Everybody was in offices. Lots of us did share offices with other people. My office mates were always good people to work with. It was nice, actually, to share an office, because you could learn a lot. The people you were sitting with were often on your team or on a related team, so you could figure out lots of stuff about what it was like to support different products. But our offices weren&amp;rsquo;t all together for the team, so you had neighbors who worked in completely different parts of the organization.&lt;/p&gt;
&lt;p&gt;One of the neighbors had a little nameplate that mentioned this person was an Evangelist. I don&amp;rsquo;t even know what team this person was on. It was a man, and the only things I knew about this Evangelist were that their door to their office was usually shut, and they were often yelling angrily into a telephone.&lt;/p&gt;
&lt;p&gt;I was just like: I don&amp;rsquo;t know exactly what this job is, I don&amp;rsquo;t know if that the job is for really angry people, or if this just happens to be a really angry person: but there seems to be a &lt;em&gt;lot&lt;/em&gt; of yelling involved. To this day I&amp;rsquo;m surprised by that. Even now, I cannot reconcile what all of this anger and yelling had to do with this person&amp;rsquo;s job. In my job as an Evangelist there is &lt;em&gt;not&lt;/em&gt; a lot of yelling, there is not a lot of anger, and I don&amp;rsquo;t even use the phone that much. So everything is really different from that first encounter with an Evangelist. But it did teach me that different Evangelists may have very very different jobs, because that is not at all the job that I&amp;rsquo;m in now.&lt;/p&gt;
&lt;h2 id="rebranding-evangelist-to-developer-advocate"&gt;Rebranding: &amp;lsquo;Evangelist&amp;rsquo; to &amp;lsquo;Developer Advocate&amp;rsquo;&lt;/h2&gt;
&lt;p&gt;These days a lot of people who do the job of what was formerly known as Evangelists are changing their job title, because the word &amp;lsquo;Evangelist&amp;rsquo; has religious overtones. To many people I think it brings up the Crusades, and it brings up violence. I don&amp;rsquo;t know if that&amp;rsquo;s related to the angry person in their office screaming into the phone or not. But at Microsoft, for example, I do know that many evangelists now have the job title Developer Advocate.&lt;/p&gt;
&lt;p&gt;I appreciate why the name might change, but I don&amp;rsquo;t know if Developer Advocate is the perfect name, either. When I think of an advocate it brings up to me someone you might get if you were in a difficult legal proceeding or if you were in a tough healthcare situation and you needed someone to advocate for you. It represents being a little bit helpless.&lt;/p&gt;
&lt;p&gt;Maybe that&amp;rsquo;s not the right understanding of Advocates. Maybe that&amp;rsquo;s a bias on my part. But naming things is about understanding cultural bias. Is Developer Advocate a better name than Evangelist? Maybe. But it isn&amp;rsquo;t a name I&amp;rsquo;m rushing out to adopt &amp;ndash; not yet.&lt;/p&gt;
&lt;p&gt;I feel like I kind of haven&amp;rsquo;t come up with the perfect job title yet.&lt;/p&gt;
&lt;h2 id="so-what-does-an-evangelist-do"&gt;So What Does an Evangelist Do?&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s talk about what Evangelists actually do. A lot of what I do has to do with communication between my company and our customers, and our potential customers out in the wild. This is communication that goes two ways.&lt;/p&gt;
&lt;p&gt;One of my main tasks is figuring out: what are the difficult things that people are encountering, what are the problems that people really need to solve? How do our products or different techniques related to our products help with that? That is a big part of my job: Patterns and practices that can help people be more successful.&lt;/p&gt;
&lt;p&gt;Now, the two-way communication involves both listening to people about what&amp;rsquo;s difficult and what&amp;rsquo;s hard (which our products could help with) AND finding where our products could improve. Identifying: what are those pain points that our existing products help with, AND what might we be able to do with them that could really help fill this need?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m tasked with channeling communication back to our development teams and saying, hey, here&amp;rsquo;s what I&amp;rsquo;m hearing from our customers. I get asked by our development teams a ton: what are you hearing from people in the marketplace? What are you hearing from consultants? What are you hearing from potential customers? What are you hearing from people at conferences? They really want to know, what are the opportunities we have, what&amp;rsquo;s working well with people, what could we do better?&lt;/p&gt;
&lt;p&gt;When listening to a customer, the job of an Evangelist is not &lt;em&gt;only&lt;/em&gt; to understand, okay there&amp;rsquo;s a product that could help you out. The job of an Evangelist is also to understand patterns about how people work. If we are going to apply a technology or a product or a process, what are the things that will actually make a team successful at that? What are the ways that people interact that need to change? What are the dependencies on really making this work well?&lt;/p&gt;
&lt;p&gt;The idea isn&amp;rsquo;t just to sell the products. In my talks, I&amp;rsquo;m going to talk about things where, yeah, our products could make it easier. But there&amp;rsquo;s always a bunch of different ways to do things. When I design talks, I&amp;rsquo;m interested in thinking about: what are the ways to make people successful? Yes, if our products fit into this, that&amp;rsquo;s amazing. And I do have a bias, because I do have an employer, right? I want to be clear about that all the time. Evangelists aren&amp;rsquo;t unbiased and neutral. But part of the job is also to be quite open, and to not only think about the products, but to also think about how people work and how people can be successful: even if parts of that are outside of the products. Or even if our products aren&amp;rsquo;t required to make you successful.&lt;/p&gt;
&lt;p&gt;Because the truth about the modern world and technology is you can absolutely write a bunch of code yourself to do a lot of things. Is it gonna take you a long time? Yes. But there&amp;rsquo;s always more than one way to do something. Buying products from different vendors can make your life easier, though.&lt;/p&gt;
&lt;p&gt;So, to me, the point of being an Evangelist is really about helping people get set up to succeed. The parts I&amp;rsquo;m gonna be the best at, the parts I&amp;rsquo;m gonna look at the most are in the areas around where my company&amp;rsquo;s focus is. Because in fact, I am really passionate about that.&lt;/p&gt;
&lt;p&gt;I took an Evangelist job at a place where I was passionate about what we are doing. I wouldn&amp;rsquo;t have taken an Evangelist job if I didn&amp;rsquo;t think these were important problems to solve, if I didn&amp;rsquo;t think they were good tools to solve the problems.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really hard to say this in a nutshell, but I think an Evangelist is someone who helps people be successful with the technology from that company&amp;ndash; and further helps set people up for making an informed decision about how they can be successful. What this ends up meaning is Evangelist may be useful to you even if you&amp;rsquo;re not a customer of that company&amp;rsquo;s products. Because when it comes to a good Evangelist, they&amp;rsquo;re giving you information that &amp;ndash; yeah, it&amp;rsquo;s gonna really help you if you use that company&amp;rsquo;s products, but they&amp;rsquo;re also giving you really valuable information that&amp;rsquo;s going to have implications agnostic of what products you&amp;rsquo;re using.&lt;/p&gt;
&lt;p&gt;For me, I want to deliver value and insights about DevOps however you&amp;rsquo;re doing DevOps. I want it to be valuable to you. I would love it if you would use our products, but even if you aren&amp;rsquo;t, in everything I do I want there to be takeaways that are valuable. Even if you&amp;rsquo;re not doing DevOps right now, the information can be useful if you&amp;rsquo;re keeping it in the possible things you might do. If you &lt;em&gt;are&lt;/em&gt; doing DevOps now, I want to include concepts and patterns you can work in regardless of the products that you&amp;rsquo;re using.&lt;/p&gt;
&lt;h2 id="my-job-at-redgate-combines-evangelism-with-involvement-in-the-sales-process"&gt;My Job at Redgate Combines Evangelism with Involvement in the Sales Process&lt;/h2&gt;
&lt;p&gt;An interesting thing about my job is &amp;ndash; my job personally is not a &amp;ldquo;pure Evangelist job&amp;rdquo;. (I don&amp;rsquo;t know if there is such a thing as a pure Evangelist job.) But my job at Redgate is a mix. The job advertisement for my position said: up to 40% of your time is going to be spent working with the sales folks, as part of the sales process. But not as a salesperson, as an Evangelist.&lt;/p&gt;
&lt;p&gt;This might sound kind of weird, because I have said hey, part of Evangelism is including things that are meaningful even if you aren&amp;rsquo;t using the products. That&amp;rsquo;s still true.&lt;/p&gt;
&lt;p&gt;The interesting thing I think about sales: and I think this is an evolution of the sales process, is more and more companies need to tap into insights about the customer and really understand the customer&amp;rsquo;s problems. Companies are turning to different models of purchase, different subscription models. Organizations don&amp;rsquo;t want to sell you something you buy one time. They want to sell something that you &lt;em&gt;renew&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Renewal is incredibly important to software companies. The points in sales is not just to sell a product once, you need your customers to use your products and to become successful with them, because you want them to continue happily using (and renewing) your product in the future. That is a huge important thing. So really understanding where the customer is coming from, what their problems are, and how to solve those problems is a very important part of the sales process.&lt;/p&gt;
&lt;h2 id="working-with-customers-is-the-best-part-of-my-job"&gt;Working with Customers Is the Best Part of My Job&lt;/h2&gt;
&lt;p&gt;My absolute favorite part of my job is interacting with new and renewing customers as part of the sales process. Because when you interact with potential customers and existing customers, you learn about all these different real world scenarios. I think the value that I provide to Redgate as an Evangelist is that I&amp;rsquo;ve been a database person for twenty years. For a long time, I&amp;rsquo;ve been working with how to write code, how to optimize SQL Servers, how to optimize processes. I&amp;rsquo;m always learning more. So in terms of my experience, it helps me really understand where customers are coming from when they&amp;rsquo;re struggling with: how do we safely deliver database changes at a high rate? How do we do this without overworking our people so that they&amp;rsquo;re dragging in the next morning and aren&amp;rsquo;t even awake enough to do code review? How do we optimize this process and make happy teams that work well, that have stable systems, and we have everything humming perfectly&amp;ndash; so we can really churn changes through?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s not easy, but my job as an Evangelist is to have insights into: how do we safely make these changes? Working with different customers, it resonates with so many different experiences I&amp;rsquo;ve had.&lt;/p&gt;
&lt;p&gt;Every software development group is unique. Everyone has their own problems, and everybody has a certain amount of anti patterns that work for us. The job isn&amp;rsquo;t just, hey, there&amp;rsquo;s these best practices. It&amp;rsquo;s much more about figuring out: how do we come up with unique ways to solve these problems and get to the result we want. We&amp;rsquo;re gonna follow a lot of best practices, but probably we can&amp;rsquo;t just implement &lt;em&gt;all&lt;/em&gt; these best practices. Because there&amp;rsquo;s always unique requirements and unique factors that mean not every best practice fits.&lt;/p&gt;
&lt;p&gt;So a lot of what I do is listen for: what are the really important requirements, and how do we map best practices to this? How do we creatively come up with solutions to the places where the best practices don&amp;rsquo;t match? That helps us picture the future state. Then there&amp;rsquo;s the further problem of: how do we get from here to the desired future state? Often we can&amp;rsquo;t do it all in one go. Often we may have to take smaller steps to get there.&lt;/p&gt;
&lt;p&gt;Working with customers in the sales process &amp;ndash; I have found that it&amp;rsquo;s the secret to making Evangelism exciting for me. Because I get to hear from customers about real problems, and I get to help brainstorm creatively to come up with solutions for those&amp;ndash; and help unstick people from getting blocked. To me that is just a ton of fun.&lt;/p&gt;
&lt;h2 id="the-culture-of-your-sales-team-matters"&gt;The Culture of Your Sales Team Matters&lt;/h2&gt;
&lt;p&gt;I do think that the culture of the sales team you&amp;rsquo;re working with matters. I&amp;rsquo;ve worked with different sales teams throughout my career, and I&amp;rsquo;m not gonna name any names here: I&amp;rsquo;m not talking about now at Redgate, I have worked with sales teams who tended to over-promise. They promised vaporware. They were selling things that don&amp;rsquo;t quite exist.&lt;/p&gt;
&lt;p&gt;Being an Evangelist in that context would be deeply uncomfortable, and probably wouldn&amp;rsquo;t work. Because a big part of being an Evangelist is being straightforward with people. Being honest and and having credibility.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t sell vaporware. I&amp;rsquo;m not going to sell vaporware. We&amp;rsquo;re working in a culture where that would be a hard fit. I do think I think more and more with software, because of the importance of renewals, because of the importance of customer happiness, I don&amp;rsquo;t think those practices are gonna survive and thrive.&lt;/p&gt;
&lt;p&gt;I think more and more sales processes are going to need to become more transparent to be successful. Otherwise, later on, people are going to be looking at those deals and they&amp;rsquo;re gonna say: why didn&amp;rsquo;t this customer renew? Well, if we sell them something that doesn&amp;rsquo;t exist, if we sell them something that doesn&amp;rsquo;t work for them, that customer is not going to end up being super satisfied.&lt;/p&gt;
&lt;p&gt;So I have been thriving as being part of the sales process, but if you&amp;rsquo;re looking at different Evangelists in other companies, their ability to be part of sales will depend on the sales culture.&lt;/p&gt;
&lt;h2 id="the-future-for-evangelists--developer-advocates"&gt;The Future for Evangelists / Developer Advocates&lt;/h2&gt;
&lt;p&gt;I think Evangelist jobs are great. It&amp;rsquo;s definitely a specific personality type: you have to like to talk, you have to like to listen, you have to like to interact with people, as well as create presentations and things like that. But if you are a person who is interested in teaching and in learning, it can be a fantastic fit.&lt;/p&gt;
&lt;p&gt;My job does technically sit within a marketing department. I think that&amp;rsquo;s great. In the past, I thought of marketing as being just a department that put out a good image. &amp;ldquo;We need to make things look good.&amp;rdquo; More and more, that is changing.&lt;/p&gt;
&lt;p&gt;With the business changes that are happening inside companies &amp;ndash; with the &amp;ldquo;digital transformations&amp;rdquo; that get talked about at the executive level &amp;ndash; the role of marketing is about helping the company have insight into the customer.&lt;/p&gt;
&lt;p&gt;What is the customer saying? What is the customer doing? What resonates with the customer? What excites the customer? What frustrates the customer? These insights are incredibly critical to helping a company survive both in terms of the messages you&amp;rsquo;re giving to people &amp;ndash; because you want to help people understand when you can solve their biggest pains. But also in terms of shaping the product design. Customers can easily compare and easily switch service providers more quickly than ever using phones and computers. People have choice.&lt;/p&gt;
&lt;p&gt;We have more and more interesting ways of delivering messages to people, too - and I think Evangelists are a really important part of that. That has to do both with reaching people through things like podcasts, through things like Twitch, through trying out new communication methods.&lt;/p&gt;
&lt;p&gt;But also in terms of listening to the customers, I get insights from customers in Slack channels, for example the SQL Server community Slack channel. Sometimes I get them by email, I get them by messages on my website. I also get them through that contact with customers. The great thing about that contact with customers is that I can learn in-depth about: what are the problems that you&amp;rsquo;re facing? What are the real pains you have? What&amp;rsquo;s really important to you, and what is the best plan to get there?&lt;/p&gt;
&lt;p&gt;Do our company&amp;rsquo;s products fit in that plan? Sometimes they will. Sometimes they won&amp;rsquo;t. The success of marketing and the success of sales is finding places where it really works, because those are going to be the customers that not only buy, but the customers that renew. The customers that tell other customers: hey we found a great way to solve these problems using those solutions.&lt;/p&gt;
&lt;p&gt;So, have I found a short answer to what an evangelist that I could say at passport control? Well, to be honest, at passport control, I think it&amp;rsquo;s just easier to say that I am a software developer or sales engineer. We can all describe our jobs in different ways, right? My job is not a sales engineer, but a related job title is a little bit easier to explain to someone who doesn&amp;rsquo;t work in software. For better or for worse, the term &amp;lsquo;Evangelist&amp;rsquo; is just very heavily loaded.&lt;/p&gt;
&lt;p&gt;If you have ideas about the best possible job title for an Evangelist, I would love to hear it &amp;ndash; because I still haven&amp;rsquo;t come up with that perfect term yet. I like the term Developer Advocate, but I&amp;rsquo;m still not 100% sold that it&amp;rsquo;s the best way to describe the job.&lt;/p&gt;
&lt;p&gt;So, anyhow, this episode is for all of those have you been asking, &amp;ldquo;hey Kendra, what is it that you&amp;rsquo;ve been doing these days?&amp;rdquo; I&amp;rsquo;ve got some more episodes in the queue coming up, I&amp;rsquo;ve got some more questions to answer. Looking forward to talking to you folks again soon, and making Dear SQL DBA more regularly again. Thanks, folks!&lt;/p&gt;</description></item><item><title>State vs Migration for Database Source Control: Decide Based on One Question</title><link>https://kendralittle.com/2019/01/23/state-vs-migration-for-database-source-control-the-core-question/</link><pubDate>Wed, 23 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/23/state-vs-migration-for-database-source-control-the-core-question/</guid><description>&lt;p&gt;One controversial topic in database development is how to properly store and deploy database changes.&lt;/p&gt;
&lt;p&gt;This is generally described as choosing between two options, which are approximately as easy to understand as Greek philosophy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;State based&lt;/strong&gt;: A Platonic view of the database as a snapshot of a set of forms in a given state at a point in time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migrations&lt;/strong&gt;: An Aristotelian view of the database defined as a series of scripts which generate change over time&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-24-12-2018_23-36-15.jpg"
alt="Bust of Developocritus, the Forgotten Greek Philosopher" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Yeah, I never really liked arguing about philosophers, either.&lt;/p&gt;
&lt;p&gt;Scratch all that. There&amp;rsquo;s a simple question that you can use to decide whether a state-based or migrations-based approach is right for a given database.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s that question:&lt;/p&gt;
&lt;h2 id="do-you-want-at-least-95-of-your-database-changes-to-deploy-using-auto-generated-code"&gt;Do You Want at Least 95% of Your Database Changes to Deploy Using Auto-Generated Code?&lt;/h2&gt;
&lt;p&gt;There you go, that&amp;rsquo;s it.&lt;/p&gt;
&lt;p&gt;Look back on your life-long experience with Clippy, with Siri, with every automated telephone system you&amp;rsquo;ve called in the past, including those where you ended up yelling &amp;ldquo;CANCEL MY ACCOUNT!&amp;rdquo; or &amp;ldquo;OPERATOR! PLEASE CAN I SPEAK TO AN OPERATOR?!?!&amp;rdquo; into the line because you were stuck in a loop.&lt;/p&gt;
&lt;p&gt;Think about Alexa, who may get into conversations with your television sometimes. Think about the driving directions from Waze that have you make four left turns in a row. Think about those times when you wonder if Google Maps is sending you somewhere simply so it can pick up traffic info, or if it really thought that was a good idea.&lt;/p&gt;
&lt;p&gt;If you think about those examples and want to use un-modified computer generated database change scripts 95% of the time, a &lt;strong&gt;primarily state-based approach&lt;/strong&gt; is right for you.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because a state-based approach looks at the current state of the in source control, compares it against a live database representing the desired state, and generates the shortest &amp;ldquo;directions&amp;rdquo; to get from one to the other.&lt;/p&gt;
&lt;p&gt;If you want to give custom directions 5% of the time or more, a &lt;strong&gt;primarily migrations based approach&lt;/strong&gt; is right for you.&lt;/p&gt;
&lt;h2 id="why-95"&gt;Why 95%?&lt;/h2&gt;
&lt;p&gt;There are 50 ways to leave your lover, and there are definitely more than two ways to store and deploy your database changes.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because vendors have created hybrid versions between state and migration approaches that allow you to primarily use one approach, and occasionally use a bit of the other.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Disclosure&lt;/strong&gt;: At the time I wrote this article, I worked for one of those vendors. Here's a whitepaper where they talk about state-first vs migration-first, and why they offer hybrids rather than absolutes: &lt;a href="https://assets.red-gate.com/solutions/database-devops/developing-deploying-databases-inside-visual-studio.pdf"&gt;developing-deploying-databases-inside-visual-studio.pdf&lt;/a&gt;.
&lt;/div&gt;
&lt;p&gt;But these two approaches are difficult to unify, so even a &amp;ldquo;hybrid approach&amp;rdquo; has a strong side.&lt;/p&gt;
&lt;h2 id="do-you-mean-migrations-first-tools-dont-help-me-write-sql"&gt;Do You Mean Migrations-First Tools Don&amp;rsquo;t Help Me Write SQL?&lt;/h2&gt;
&lt;p&gt;Nope. Migrations based database deployment tools may have very nice engines to auto-generate changes for you, too.&lt;/p&gt;
&lt;p&gt;The differences are that a migrations-first tool generally makes it &lt;em&gt;much&lt;/em&gt; easier for humans to review change code and customize those scripts &amp;ndash; making it easier for you to control exactly what happens, and how many steps are taken to make it happen.&lt;/p&gt;</description></item><item><title>DBA Jobs: Threats and Opportunities (Dear SQL DBA Episode 66)</title><link>https://kendralittle.com/2019/01/18/dba-jobs-threats-and-opportunities-dear-sql-dba-episode-66/</link><pubDate>Fri, 18 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/18/dba-jobs-threats-and-opportunities-dear-sql-dba-episode-66/</guid><description>&lt;p&gt;Jobs change over time, and database administrator jobs are no different. In this 35 minute recorded Twitch livestream (my first ever!) I talk about threats to DBA jobs and the related opportunities.&lt;/p&gt;
&lt;h2 id="about-this-episode"&gt;About This Episode&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s been a few months since I published an episode of Dear SQL DBA. I like the idea of doing future episodes with livestreaming on &lt;a href="https://www.twitch.tv/kendra_little"&gt;my Twitch channel&lt;/a&gt;, so I&amp;rsquo;m hoping to make this a regular thing again.&lt;/p&gt;
&lt;p&gt;The audio in this episode isn&amp;rsquo;t perfect, but I reminded myself that perfect is the enemy of good. I&amp;rsquo;ll work on getting audio quality back up in the next episode.&lt;/p&gt;
&lt;h2 id="watch-the-episode"&gt;Watch the Episode&lt;/h2&gt;
&lt;p&gt;And with that, here&amp;rsquo;s the recording:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/4hksGvt-VYI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>3 Key Points from My Upcoming Talk: DevOps: What, Who, Why, and How?</title><link>https://kendralittle.com/2019/01/17/3-key-points-from-my-upcoming-talk-devops-what-who-why-and-how/</link><pubDate>Thu, 17 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/17/3-key-points-from-my-upcoming-talk-devops-what-who-why-and-how/</guid><description>&lt;p&gt;Next week, I&amp;rsquo;m giving a free webcast for Redgate on DevOps fundamentals. DevOps is something I am a big proponent of for database administrators, developers, and company leaders.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll cover three points which are often the source of misunderstandings.&lt;/p&gt;
&lt;h2 id="developer-productivity-is-a-top-concern-of-c-level-executives"&gt;Developer Productivity Is a Top Concern of C-Level Executives&lt;/h2&gt;
&lt;p&gt;Implementing DevOps isn&amp;rsquo;t something you do in an afternoon. Often, DevOps implementations begin from the C-suite as part of a digital transformation effort. DevOps can also be originated from small teams in the company who transform their own practices, share their success with the company, and enlist executive support to spread these practices to other teams.&lt;/p&gt;
&lt;p&gt;Many DBAs and developers worry about the costs of implementing DevOps: not only the costs for tools, but also slow-downs in delivering new features while working on important projects that are the foundation of DevOps, such as standardizing the database code in Version Control and writing tests.&lt;/p&gt;
&lt;p&gt;We should all be less worried about opening this conversation with company leaders, however. In September, 2018, Stripe performed &lt;a href="https://stripe.com/reports/developer-coefficient-2018"&gt;a study with Harris Poll on software engineering efficiency&lt;/a&gt;. They surveyed more than 1,000 C-level executives:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;96% of C-Level execs polled believe that increasing productivity of developers is a high or medium priority&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Slowdowns in productivity can be painful. But if they result in increasing the overall productivity of developers afterward, that slowdown pays off quickly.&lt;/p&gt;
&lt;p&gt;The study overall found that a &amp;ldquo;lack&amp;rdquo; of developers is not the main problem: instead the problem is leveraging existing talent within companies better. DevOps directly addresses this problem.&lt;/p&gt;
&lt;h2 id="having-a-team-who-does-devops-for-you-doesnt-work"&gt;Having a Team Who Does DevOps &amp;ldquo;for You&amp;rdquo; Doesn&amp;rsquo;t Work&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s common for companies seeking to release code changes faster to implement a &amp;ldquo;DevOps team.&amp;rdquo; While specialists can help larger teams adapt DevOps practices, inspire DevOps culture, and suggest patterns for work that get the cycle of continuous improvement started, these teams can&amp;rsquo;t do DevOps &amp;ldquo;for&amp;rdquo; other teams.&lt;/p&gt;
&lt;p&gt;Andrew Hatch, Platform Engineering Manager at SEEK, has written about why SEEK created a DevOps team, what happened with the team, and why they ultimately &lt;a href="http://bit.ly/2Fv7dFv"&gt;decided they no longer need a DevOps Team&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In his article, Andrew Shared that the DevOps team took over the build, deployment, and operational support for the organization&amp;rsquo;s critical websites, but:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We had made rapid advances in our delivery processes but we still faced torrid nights on-call with software systems straining under the sheer volume of product being deployed to them.”&lt;/p&gt;
&lt;p&gt;&lt;a href="http://bit.ly/2Fv7dFv"&gt;Why We Don&amp;rsquo;t Need a DevOps Team&lt;/a&gt; by Andrew Hatch&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Doing DevOps is not &lt;em&gt;only&lt;/em&gt; about release tempo. Other measures regarding stability are hugely important:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time to restore service&lt;/li&gt;
&lt;li&gt;Rate of failure of changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By spreading the DevOps culture into developer and IT teams and making them autonomous units who could support their own releases, the team at SEEK were able to improve quality and maintain their higher release frequency.&lt;/p&gt;
&lt;h2 id="doing-well-at-devops-means-including-the-database"&gt;Doing Well at DevOps Means Including the Database&lt;/h2&gt;
&lt;p&gt;Dr. Nicole Forsgren of &lt;a href="https://devops-research.com/about.html"&gt;DevOps Research and Assessment&lt;/a&gt; (now part of Google) is an internationally known researcher into DevOps practices. In the &lt;a href="https://devops-research.com/research.html"&gt;2018 State of DevOps Report by DORA&lt;/a&gt;, they found that&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Teams that do well at continuous delivery store database changes as scripts in version control and manage these changes in the same way as production application changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://devops-research.com/research.html"&gt;2018 State of DevOps Report, DORA&lt;/a&gt;, Dr. Nicole Forsgren, Jez Humble, Gene Kim&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Making this work well doesn&amp;rsquo;t mean getting rid of database specialists. Instead, DBAs are part of the DevOps culture:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Furthermore, when changes to the application require database changes, these teams discuss them with the people responsible for the production database and ensure the engineering team has visibility into the progress of pending database changes. &lt;strong&gt;When teams follow these practices, database changes don’t slow them down, or cause problems when they perform code deployments.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(Emphasis mine) &lt;a href="https://devops-research.com/research.html"&gt;2018 State of DevOps Report, DORA&lt;/a&gt;, Dr. Nicole Forsgren, Jez Humble, Gene Kim&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="i-have-lots-more-to-share"&gt;I have lots more to share!&lt;/h3&gt;
&lt;p&gt;In my upcoming webcast, we&amp;rsquo;ll talk more about what DevOps is, who is involved in DevOps, and the impact DevOps has on organizations.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://register.gotowebinar.com/register/853744786602494467?source=KB"&gt;Register here to join me in next week&amp;rsquo;s webcast&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Watch All My Free PASS Summit Recordings and More Videos at Pass.org</title><link>https://kendralittle.com/2019/01/16/watch-all-my-free-pass-summit-recordings-and-more-videos-at-pass-org/</link><pubDate>Wed, 16 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/16/watch-all-my-free-pass-summit-recordings-and-more-videos-at-pass-org/</guid><description>&lt;p&gt;A magical thing happened this week in the SQL Community Slack (it&amp;rsquo;s free to join, &lt;a href="https://dbatools.io/slack/"&gt;sign up here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In the midst of a discussion about the cost of attending conferences, &lt;a href="https://twitter.com/bennidejagere"&gt;Benni De Jagere&lt;/a&gt; shared the following &lt;a href="https://twitter.com/cathrinew/status/1084804828818169856"&gt;tweet from Cathrine Wilhelmsen&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Did you know that ALL the session recordings from PASS Summit 2017 (and earlier) are available for free? :) Get your learning on here: &lt;a href="https://pass.org/Learning/Recordings/Listing.aspx?category=Summit"&gt;https://pass.org/Learning/Recordings/Listing.aspx?category=Summit&lt;/a&gt; #SQLPass #PASSsummit #SQLFamily&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I follow Cathrine, but apparently I need to follow her more closely, as I&amp;rsquo;d missed this tweet on the 14th. I had no idea these recordings were free and searchable.&lt;/p&gt;
&lt;h2 id="these-free-sessions-include-way-more-than-the-summits"&gt;These Free Sessions Include Way More Than the Summits&lt;/h2&gt;
&lt;p&gt;I checked out which recordings are available, and my mind was blown &amp;ndash; it&amp;rsquo;s not just past PASS Summit recordings (excluding the 2018 Summit, most of which are not currently free), but also user group talks, 24 Hours of PASS Recordings, everything!&lt;/p&gt;
&lt;h2 id="how-do-i-watch"&gt;How do I watch?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Head to the &lt;a href="https://www.youtube.com/channel/UCCN1vyLawxrXAiTQoi3lNow"&gt;PASStv youtube channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Search for recordings by topic or speaker name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s about it. It&amp;rsquo;s a treasure trove of stuff.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: these instructions updated in May 2021, following Redgate's publishing of past PASS Summit content to YouTube.
&lt;/div&gt;
&lt;h2 id="a-list-of-my-pass-sessions"&gt;A list of my PASS Sessions&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a list of my sessions on the PASS Site, along with notes of their &amp;ldquo;freshness&amp;rdquo; today:&lt;/p&gt;
&lt;h3 id="2019"&gt;2019&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Get Inspired: Celebrate the Careers of Three DevOps Heroes with Kendra Little
&lt;ul&gt;
&lt;li&gt;WIT Virtual Chapter, Jan 2019&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2018"&gt;2018&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fix My Functions: Speeding Up Scalar and Table Valued UDFs
&lt;ul&gt;
&lt;li&gt;Summit 2018&lt;/li&gt;
&lt;li&gt;Note: this one isn&amp;rsquo;t showing as free on the &amp;lsquo;Learning&amp;rsquo; site, but it was livestreamed during the Summit, so it&amp;rsquo;s available via other channels. &lt;a href="https://kendralittle.com/2018/11/14/fix-my-functions-speeding-up-scalar-and-table-valued-udfs-video/"&gt;Watch the recording&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How Keys &amp;amp; Included Columns Work by Kendra Little
&lt;ul&gt;
&lt;li&gt;Data Architecture Virtual Chapter, June 2018&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why is that Data Wrong? How Choosing the Wrong Isolation Level Causes Bad Results
&lt;ul&gt;
&lt;li&gt;24 Hours of PASS, June 2018&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2017"&gt;2017&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;When Partitioning Indexes Hurts Performance (and How to Fix It)
&lt;ul&gt;
&lt;li&gt;PASS Summit, 2017&lt;/li&gt;
&lt;li&gt;Freshness ☺ - batch mode for rowstore is coming up soon, but other than that it&amp;rsquo;s quite current&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why Did My Clever Index Change Backfire?
&lt;ul&gt;
&lt;li&gt;PASS Summit, 2017&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SSMS Shortcuts &amp;amp; Secrets - Kendra Little
&lt;ul&gt;
&lt;li&gt;DBA Fundamentals Virtual Chapter, Sept 2017&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why Did My Clever Index Change Backfire?
&lt;ul&gt;
&lt;li&gt;24 Hours of PASS, Summit Preview, 2017&lt;/li&gt;
&lt;li&gt;Freshness 💯 - note, this is a preview of the live summit session above&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2016"&gt;2016&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The Great Performance Robbery: Locking Problems and Solutions
&lt;ul&gt;
&lt;li&gt;PASS Summit 2016&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;3 Skills Every Junior DBA Must Know
&lt;ul&gt;
&lt;li&gt;DBA Fundamentals Virtual Chapter, July 2016&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2015"&gt;2015&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Take the SQL Server Index Quiz!
&lt;ul&gt;
&lt;li&gt;24 Hours of PASS Summit Preview, 2015&lt;/li&gt;
&lt;li&gt;Freshness ☺&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How to Configure Quorum in SQL Server
&lt;ul&gt;
&lt;li&gt;HA/DR Virtual Group, May 2016&lt;/li&gt;
&lt;li&gt;Freshness &amp;ndash; a lot has changed in this area since 2015 😑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2014"&gt;2014&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;World&amp;rsquo;s Worst Performance Tuning Techniques
&lt;ul&gt;
&lt;li&gt;PASS Summit 2014&lt;/li&gt;
&lt;li&gt;Freshness 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why Does SQL Server Keep Asking for this Index?
&lt;ul&gt;
&lt;li&gt;PASS Summit 2014&lt;/li&gt;
&lt;li&gt;Freshness - main points are still true, but I haven&amp;rsquo;t tested the demo against higher compatibility levels to see if the same execution plans are still generated&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2013"&gt;2013&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How to Tell When Storage Is a Problem
&lt;ul&gt;
&lt;li&gt;PASS Summit 2013&lt;/li&gt;
&lt;li&gt;Freshness is surprisingly high &amp;ndash; I&amp;rsquo;m talking about interpreting DMVs and perf counters here, not which SAN to buy, so it&amp;rsquo;s still spot on 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2012"&gt;2012&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Index Psychiatry: Diagnose and Treat the Top 5 Disorders
&lt;ul&gt;
&lt;li&gt;PASS Summit 2012&lt;/li&gt;
&lt;li&gt;Freshness - I show the sp_BlitzIndex procedure in this talk. That procedure has changed a lot since the talk, so it&amp;rsquo;ll look different. Concepts discussed are still true for disk based nonclustered rowstore 💯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL Server First Responder Kit
&lt;ul&gt;
&lt;li&gt;PASS Summit 2012&lt;/li&gt;
&lt;li&gt;Freshness - medium 😑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2011"&gt;2011&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No More Bad Dates: Best Practices for Working With Dates and Times
&lt;ul&gt;
&lt;li&gt;PASS Summit 2011&lt;/li&gt;
&lt;li&gt;Freshness - medium 😑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="thanks-to-pass-for-publishing-these-videos-for-free"&gt;Thanks to PASS for publishing these videos for free!&lt;/h2&gt;
&lt;p&gt;I had a lot of fun looking through my own videos, and I &lt;em&gt;love&lt;/em&gt; having this library of free videos as a learning site for fundamental concepts.&lt;/p&gt;</description></item><item><title>Watch: Can This Team Succeed at DevOps? Panel Discussion</title><link>https://kendralittle.com/2019/01/10/watch-can-this-team-succeed-at-devops-panel-discussion/</link><pubDate>Thu, 10 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/10/watch-can-this-team-succeed-at-devops-panel-discussion/</guid><description>&lt;p&gt;I recently participated in a panel discussion for the &lt;a href="https://devops.pass.org/"&gt;SQL PASS DevOps virtual chapter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Watch our discussion about how to make three different teams successful at database DevOps.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/vC77Dt4w8-U?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="session-overview"&gt;Session Overview&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;DevOps sounds great in theory, but in reality it&amp;rsquo;s tricky to transform your people, process, and tools.&lt;/p&gt;
&lt;p&gt;In this interactive, poll-packed panel discussion, we will use real-world scenarios to clarify what DevOps principles are and how they help reduce manual work and improve productivity for software developers and database administrators.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll step through situations that are tricky when it comes to making database changes, sharing patterns to avoid and how to approach and conquer problematic entrenched processes.&lt;/p&gt;
&lt;p&gt;This session is designed to be accessible to both beginners and advanced practitioners: we&amp;rsquo;ll talk through definitions of DevOps terms and patterns and will encourage audience discussion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="your-panelists"&gt;Your Panelists&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Kendra Little - Product Evangelist, Redgate&lt;/li&gt;
&lt;li&gt;Hamish Watson - Alchemist, Morph iT&lt;/li&gt;
&lt;li&gt;William Durkin - Data Platform Architect, Data Masterminds&lt;/li&gt;
&lt;li&gt;Rob Sewell - Beard Twizzler&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>What 'Digital Transformation' Means, and How You Can Use It to Advance Your Career (video)</title><link>https://kendralittle.com/2019/01/03/what-digital-transformation-means-and-how-you-can-use-it-to-advance-your-career-video/</link><pubDate>Thu, 03 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/03/what-digital-transformation-means-and-how-you-can-use-it-to-advance-your-career-video/</guid><description>&lt;p&gt;I recently spoke at the &lt;a href="https://groupby.org/"&gt;GroupBy free online conference&lt;/a&gt;. It was loads of fun, and the recordings from the event are now available.&lt;/p&gt;
&lt;p&gt;In the hour-long session below, I explore what executives mean when they describe a &amp;lsquo;digital transformation&amp;rsquo;, why this transformation is happening across all industries, and how understanding this gives developers and database administrators an advantage in building their careers.&lt;/p&gt;
&lt;p&gt;Even if you hate buzzwords, the big ones signify critical cultural changes. Digital transformation is one of those buzzwords, and it&amp;rsquo;s worth understanding what it really means.&lt;/p&gt;
&lt;p&gt;I explain what motivates CEOs to modify their business models in a digital transformation, and I share patterns and anti-patterns of companies that have attempted these transformations with different results.&lt;/p&gt;
&lt;p&gt;By the end of the session, you&amp;rsquo;ll have an understanding of the core ideas and philosophies behind digital transformation that will help you prioritize what to learn, guide your interactions at work, and strategize your career path.&lt;/p&gt;
&lt;h2 id="watch-the-session"&gt;Watch the Session&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/g558T1vbZYQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Do 75 Percent of Data Breaches Really Come from Insiders?</title><link>https://kendralittle.com/2019/01/02/do-75-of-data-breaches-really-come-from-insiders/</link><pubDate>Wed, 02 Jan 2019 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2019/01/02/do-75-of-data-breaches-really-come-from-insiders/</guid><description>&lt;p&gt;There&amp;rsquo;s a lot of information out there on data breaches. I&amp;rsquo;ve written before about &lt;a href="https://kendralittle.com/2018/12/03/where-do-data-breaches-come-from/"&gt;one source that I trust: the Verizon Data Breach Report (DBIR)&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/hackerman.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;The 2018 DBIR studied a sample of 2,216 confirmed data breaches, and of these it found that 28% involved internal actors. The DBIR uses a publicly accessible &lt;a href="https://github.com/vz-risk/VCDB"&gt;database of security incidents&lt;/a&gt;, and applies quality filters to data before including it in the report.&lt;/p&gt;
&lt;h2 id="only-28-i-heard-that-75-of-breaches-come-from-insiders"&gt;Only 28%? I Heard That 75% of Breaches Come from &amp;ldquo;Insiders&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;Different studies sample different breaches, so it&amp;rsquo;s natural that there would be some variance on findings about who is behind breaches. However, I heard about a report where the variance was enough that I wanted to look into it: a presentation at the PASS Summit in 2018 cited a 2017 article which found that three quarters of data breaches came from &amp;ldquo;insiders.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This figure seems very high to me. Every day we hear about data breaches in the news: from &lt;a href="https://kendralittle.com/2018/12/03/where-do-data-breaches-come-from/"&gt;bagels&lt;/a&gt; to literally &lt;a href="https://www.businessinsider.com/data-hacks-breaches-biggest-of-2018-2018-12"&gt;everything else&lt;/a&gt;. Could three quarters of these really be due to the malice or incompetence of employees?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s find out where that number comes from.&lt;/p&gt;
&lt;h2 id="follow-the-article-trail"&gt;Follow the Article Trail&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not going to link to the articles involved in spreading this statistic, because I think they&amp;rsquo;re clickbait. I followed a trail of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A somewhat legitimate looking security article which says, &amp;ldquo;nearly three-quarters of incidents are due to insider threats.&amp;rdquo; The article doesn&amp;rsquo;t define what insider threats &lt;em&gt;are&lt;/em&gt;, but says &amp;ldquo;Not all insider threats are deliberate,&amp;rdquo; and then references a different study.&lt;/li&gt;
&lt;li&gt;The source referenced for the &amp;ldquo;nearly three-quarters&amp;rdquo; stat in that article is an ebook by a security tools retailer. In the undated eBook, they write&amp;hellip;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;According to the most recent Clearswift Insider Threat Index (CITI) report, 74% of security breaches originate from within the extended global enterprise. &amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It looks like the original source of the &amp;ldquo;75%&amp;rdquo; number is the security company Clearswift. They used to publish their &amp;ldquo;Threat Index&amp;rdquo; as a PDF, but more recent years appear to simply be simpler press releases, &lt;a href="https://www.clearswift.com/about-us/pr/press-releases/insider-threat-74-security-incidents-come-extended-enterprise-not-hacking-groups"&gt;such as this one for 2017&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-do-we-know-about-the-methodology"&gt;What Do We Know About the Methodology?&lt;/h2&gt;
&lt;p&gt;Studying data breaches is hard, for a few reasons. Not everyone wants to talk about them. Often, it&amp;rsquo;s a long time until the breach is discovered. And getting to the bottom of the breaches can be tough.&lt;/p&gt;
&lt;p&gt;The folks at Clearswift describe their research as having&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;surveyed 600 senior business decision makers and 1,200 employees across the UK, US, Germany and Australia&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.clearswift.com/about-us/pr/press-releases/insider-threat-74-security-incidents-come-extended-enterprise-not-hacking-groups"&gt;Clearswift 2017 threat index&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s not clear how many of these respondents had confirmed data breaches that impacted customers, or the nature of how the causes of the breaches were assessed.&lt;/p&gt;
&lt;p&gt;Reading the press release, here&amp;rsquo;s some clarification on the numbers for 2017:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Threats from an employee - inadvertent or malicious - make up 42% of incidents&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;When looking at the extended enterprise – employees, customers, suppliers, and ex-employees – this number reaches 74%, compared to 26% of attacks from parties unknown to the organization.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="looking-at-sources-do-they-define-data-breach-and-security-incident"&gt;Looking at Sources: Do They Define &amp;lsquo;Data Breach&amp;rsquo; and &amp;lsquo;Security Incident&amp;rsquo;?&lt;/h2&gt;
&lt;p&gt;The folks who write the Verizon DBIR are very careful about defining terms at the beginning of their report &amp;ndash; which is one of the reasons I&amp;rsquo;m such a big fan of it. Here are the definitions from the 2018 DBIR:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security incidents are: “a security event that compromises the integrity, confidentiality or availability of an information asset”. &lt;/li&gt;
&lt;li&gt;Data breaches are: &amp;ldquo;an incident that results in the confirmed disclosure (not just potential exposure) of data to an unauthorized party.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Clearswift uses both of these terms, but their threat indexes do not define them or differentiate against them. It often reads as if they use the terms interchangeably. That&amp;rsquo;s a big problem &amp;ndash; and it may be that the people who are taking their surveys aren&amp;rsquo;t sure what the definitions are, either.&lt;/p&gt;
&lt;h2 id="these-numbers-shouldnt-add-up-should-they"&gt;These Numbers Shouldn&amp;rsquo;t Add Up, Should They?&lt;/h2&gt;
&lt;p&gt;Another puzzling thing about the Clearswift numbers is that they add up a bit &lt;em&gt;too&lt;/em&gt; neatly.&lt;/p&gt;
&lt;p&gt;If 74% of attacks originate from &amp;lsquo;inside&amp;rsquo; (the extended enterprise, due to malice and accident) and 26% originate from hackers outside, then were there 0% of cases where hackers collaborated with a malicious employee? Or where hackers took advantage of a mistake?&lt;/p&gt;
&lt;p&gt;Isn&amp;rsquo;t it natural, and even likely, that many data breaches have multiple points of origin?&lt;/p&gt;
&lt;h2 id="separating-the-research-from-the-clickbait"&gt;Separating the Research from the Clickbait&lt;/h2&gt;
&lt;p&gt;When I&amp;rsquo;m reading about data breaches, I ask these questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the source study clearly referenced and available for review?&lt;/li&gt;
&lt;li&gt;Does the source study define its terms clearly?&lt;/li&gt;
&lt;li&gt;Does the source study clearly state how many distinct confirmed data breaches were analyzed?&lt;/li&gt;
&lt;li&gt;Does the source study allow multiple causes for a data breach?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If all of those are a &amp;lsquo;yes&amp;rsquo;, it&amp;rsquo;s probably not clickbait.&lt;/p&gt;
&lt;p&gt;In this case, I think it probably is.&lt;/p&gt;</description></item><item><title>Watch: The Best of 2018 and Predictions for 2019 (video)</title><link>https://kendralittle.com/2018/12/27/watch-the-best-of-2018-and-predictions-for-2019-video/</link><pubDate>Thu, 27 Dec 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/12/27/watch-the-best-of-2018-and-predictions-for-2019-video/</guid><description>&lt;p&gt;I recently got together with fellow Microsoft Data Platform MVPs Steve Jones, Kathi Kellenberger and Grant Fritchey to discuss the highlights of innovations we&amp;rsquo;ve seen in 2018 and predictions for 2019.&lt;/p&gt;
&lt;h2 id="highlights-and-predictions"&gt;Highlights and Predictions&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/QnoztgV9PyY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Adding Microsoft MVP Contributions with PowerShell: Lessons Learned Using the MVP API</title><link>https://kendralittle.com/2018/12/26/adding-microsoft-mvp-contributions-with-powershell-lessons-learned-using-the-mvp-api/</link><pubDate>Wed, 26 Dec 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/12/26/adding-microsoft-mvp-contributions-with-powershell-lessons-learned-using-the-mvp-api/</guid><description>&lt;p&gt;One of the things that brings &lt;a href="https://mvp.microsoft.com"&gt;Microsoft MVPs&lt;/a&gt; together each year is complaining about reporting community contributions to Microsoft.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-24-12-2018_17-12-23.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;This is a typical first world problem, but with a history of reporting tools ranging from temperamental Infopath forms to websites where you painstakingly click here and there for &lt;em&gt;hours&lt;/em&gt;, there have been reasons for the complaints.&lt;/p&gt;
&lt;p&gt;This year I decided to try out using PowerShell to add my contributions. This has been available for about a year thanks to &lt;a href="https://github.com/lazywinadmin/MVP/graphs/contributors"&gt;François-Xavier Cat and a few friends&lt;/a&gt;, but I&amp;rsquo;d completely forgotten that it was possible until &lt;a href="https://twitter.com/sql_williamd"&gt;William Durkin&lt;/a&gt; &lt;a href="https://twitter.com/sql_williamd/status/1062431060930297858"&gt;reminded me about it on Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First time ever, I didn&amp;rsquo;t wait until the last minute to start thinking about my annual contributions. Instead, I took a little time to learn about how this works &amp;ndash; and now I&amp;rsquo;ll keep my contributions in a spreadsheet and then upload them right before the deadline.&lt;/p&gt;
&lt;p&gt;Here are my notes on what I found, and why I&amp;rsquo;ll still wait to upload.&lt;/p&gt;
&lt;h2 id="some-setup-is-required"&gt;Some Setup Is Required&lt;/h2&gt;
&lt;p&gt;The documentation for setup is quite good. I used &lt;a href="https://github.com/lazywinadmin/MVP/blob/master/README.md#Install"&gt;the main documentation and it went very smoothly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One note: in the docs it mentions that your request will be reviewed and accepted by an administrator within a couple of business days. Mine appeared to be auto-approved and I didn&amp;rsquo;t have to wait at all, I was able to start using my subscription right away.&lt;/p&gt;
&lt;h2 id="caching-sounds-great-until-its-not"&gt;Caching Sounds Great, Until It&amp;rsquo;s Not&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;
&lt;p&gt;Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The most painful part of uploading contributions with PowerShell wasn&amp;rsquo;t getting the upload to work: it was figuring out that &lt;a href="https://github.com/lazywinadmin/MVP/issues/15"&gt;the cache for the MVP website doesn&amp;rsquo;t get cleared by PowerShell uploads which use the API.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This means that the contributions you see on your profile on the website are probably not the current version at all if you&amp;rsquo;re uploading via PowerShell, because that cache is way out of date.&lt;/p&gt;
&lt;p&gt;This is true if you are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Looking at your contributions from a logged out state&lt;/li&gt;
&lt;li&gt;Editing your contributions while logged in. The website doesn&amp;rsquo;t even invalidate the cache reliably if you&amp;rsquo;re editing your contributions, I&amp;rsquo;ve found 😂&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="workaround-export-all-your-contributions-to-a-csv-file-from-the-api-and-review-them-that-way"&gt;Workaround: Export All Your Contributions to a .csv File from the API and Review Them That Way&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m no scripting genius, but I came up with a simple command to export all my contributions for review:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Get-MVPContribution&lt;/span&gt; &lt;span class="n"&gt;-Limit&lt;/span&gt; &lt;span class="mf"&gt;500&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;export-csv&lt;/span&gt; &lt;span class="n"&gt;exportedcontributions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This also gives you the ContributionId for each of your contributions, in case you want to delete any.&lt;/p&gt;
&lt;h2 id="inserts-are-easy-updates-are-hard"&gt;Inserts Are Easy, Updates Are Hard&lt;/h2&gt;
&lt;p&gt;One of the main questions I had when starting out was whether re-running New-MVPContribution would be smart enough to identify matching existing contributions with the same date and description, and update other information, such as the &amp;lsquo;AnnualReach&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Why this matters: Microsoft doesn&amp;rsquo;t publish the criteria they use to select MVPs, but if I was them, I&amp;rsquo;d pay a lot of attention to those reach numbers.&lt;/p&gt;
&lt;p&gt;So when it comes to items like videos, I want to report the reach at the end of the review cycle, not just after I post the video.&lt;/p&gt;
&lt;p&gt;Finding: New-MVPContribution does not find and update contributions. If you rerun an import for a .csv file with contributions, it&amp;rsquo;s very easy to create duplicates.&lt;/p&gt;
&lt;h2 id="if-you-accidentally-create-duplicate-contributions-no-worries"&gt;If You Accidentally Create Duplicate Contributions, No Worries&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s simple to get a list of all your contributions using Get-MVPContribution (see my workaround above), and then &lt;a href="https://github.com/lazywinadmin/MVP/blob/master/README.md#RemoveMvpContributionMultiple"&gt;run a delete loop using the ContributionIds with code like this sample in the documentation&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="all-in-all-i-like-this-way-of-managing-contributions"&gt;All in All, I Like This Way of Managing Contributions&lt;/h2&gt;
&lt;p&gt;My new way of doing this is&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;a href="https://github.com/lazywinadmin/MVP/blob/master/README.md#NewMvpContributionMultiple"&gt;a simple spreadsheet saved as a .csv file&lt;/a&gt; to track my contributions: I&amp;rsquo;ll update it once a month with a summary of the talks that I&amp;rsquo;ve done that month, and links to videos I&amp;rsquo;ve posted.&lt;/li&gt;
&lt;li&gt;A couple of weeks before contributions are due, I&amp;rsquo;ll update the reach numbers for the videos in the spreadsheet. I&amp;rsquo;ll also add in entries for aggregate information where helpful &amp;ndash; for example, I add a single line for all my blog posts with reach information, instead of a line for each post. Then I&amp;rsquo;ll do a single upload for the year from the .csv file.&lt;/li&gt;
&lt;li&gt;After upload, I&amp;rsquo;ll manually edit a contribution in the GUI and see if this triggers a cache clear to validate display of the contributions (I&amp;rsquo;ve had mixed results). Setting a reminder to see how they display the next day isn&amp;rsquo;t a bad idea, either.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&amp;rsquo;s certainly not perfect, but it&amp;rsquo;s waaaaaaay better than an old infopath form, so I&amp;rsquo;m happy to have it.&lt;/p&gt;</description></item><item><title>Where Do Data Breaches Come From?</title><link>https://kendralittle.com/2018/12/03/where-do-data-breaches-come-from/</link><pubDate>Mon, 03 Dec 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/12/03/where-do-data-breaches-come-from/</guid><description>&lt;p&gt;I recently did a bit of research on the source of data breaches. In this post, I&amp;rsquo;ll talk a bit about my current favorite source for breach information, and a bit of what I learned.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-30-11-2018_18-22-18.jpg"
alt="A man in a zip-up flannel jacket holding a laptop awkwardly, wearing a mask and hat. Text over the photo reads, &amp;#39;HACKERMAN&amp;#39;"&gt;
&lt;/figure&gt;
&lt;h2 id="verizon-publishes-the-data-breach-investigations-report-annually"&gt;Verizon publishes the &amp;lsquo;Data Breach Investigations Report&amp;rsquo; annually &lt;/h2&gt;
&lt;p&gt;The 2018 edition of &lt;a href="https://enterprise.verizon.com/resources/reports/dbir/"&gt;this free report by Verizon Enterprise Solutions&lt;/a&gt; is the 11th edition: they&amp;rsquo;ve had some practice. The reports are extremely well detailed, and shockingly, they&amp;rsquo;re even &lt;em&gt;entertaining&lt;/em&gt; to read.&lt;/p&gt;
&lt;p&gt;The reports don&amp;rsquo;t claim to discover all data breaches. After all, not all data breaches are discovered, and those that are discovered aren&amp;rsquo;t necessarily reported.&lt;/p&gt;
&lt;h2 id="2216-breaches-analyzed"&gt;2,216 Breaches, Analyzed&lt;/h2&gt;
&lt;p&gt;The 2018 &lt;a href="https://enterprise.verizon.com/resources/reports/dbir/"&gt;report&lt;/a&gt; covers 53,000 incidents, defined as &amp;ldquo;a security event that compromises the integrity, confidentiality or availability of an information asset&amp;rdquo;. &lt;/p&gt;
&lt;p&gt;It also covers 2,216 breaches, which are defined as &amp;ldquo;an incident that results in the &lt;strong&gt;confirmed disclosure&lt;/strong&gt; (not just potential exposure) &lt;strong&gt;of data to an unauthorized party&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;These numbers (and the screenshots I&amp;rsquo;m sharing below), do NOT include  breach data involving botnets. 43,000 &amp;ldquo;successful accesses via stolen credentials&amp;rdquo; associated with botnets are handled in a special insights section of the report.&lt;/p&gt;
&lt;h2 id="are-data-breaches-caused-mainly-by-insiders-or-outsiders"&gt;Are Data Breaches Caused Mainly by Insiders or Outsiders?&lt;/h2&gt;
&lt;p&gt;A colleague of mine mentioned that he&amp;rsquo;d recently seen some numbers suggesting that data breaches were mainly perpetuated by insiders to an organization &amp;ndash; but he hadn&amp;rsquo;t been able to track down the source of those figures or substantiating data. With the number of data breaches we see these days, that&amp;rsquo;s a pretty dark view of employee-employer relationships!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the &lt;a href="https://enterprise.verizon.com/resources/reports/dbir/"&gt;Verizon report&lt;/a&gt; shows in terms of who is behind the breaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;73% perpetuated by outsiders&lt;/li&gt;
&lt;li&gt;28% involving internal actors&lt;/li&gt;
&lt;li&gt;2% involving partners&lt;/li&gt;
&lt;li&gt;2% featuring multiple parties&lt;/li&gt;
&lt;li&gt;50% carried out by organized criminal groups&lt;/li&gt;
&lt;li&gt;12% involved actors identified as nation-state or state-affiliated&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These figures are regarding those confirmed data breaches, not all security incidents. While 28% involve internal actors, the bulk of data breaches are coming from people outside the organization, finding their way in by using malware or social attacks, or by exploiting vulnerabilities created due to errors.&lt;/p&gt;
&lt;h2 id="who-can-a-database-administrator-trust"&gt;Who Can a Database Administrator Trust?&lt;/h2&gt;
&lt;p&gt;For those internal actors involved in data breaches, my first thought was, &amp;ldquo;Well, so WHO WAS IT?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s answered a couple pages later. While the exact internal actors weren&amp;rsquo;t found for all of the reported data breaches, analysis was done for 277 data breaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;72 system admin&lt;/li&gt;
&lt;li&gt;62 end user&lt;/li&gt;
&lt;li&gt;62 other&lt;/li&gt;
&lt;li&gt;32 doctor or nurse&lt;/li&gt;
&lt;li&gt;15 developer&lt;/li&gt;
&lt;li&gt;9 manager&lt;/li&gt;
&lt;li&gt;8 executives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As much as database administrators like to focus on denying permissions to developers for production, developers were &lt;em&gt;much&lt;/em&gt; less likely to be involved in data breaches than system admins.&lt;/p&gt;
&lt;p&gt;And who exactly are system admins?&lt;/p&gt;
&lt;p&gt;Well, I&amp;rsquo;m guessing that includes&amp;hellip; the DBAs. &lt;/p&gt;
&lt;h2 id="this-is-remarkable-given-that-you-dont-need-production-access-to-cause-a-data-breach"&gt;This Is Remarkable Given That You Don&amp;rsquo;t Need Production Access to Cause a Data Breach&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a pretty normal practice in an Enterprise to make copies of production data for use in internal environments. Copies of data are used by analysts, developers, product managers, marketing professionals, and more.&lt;/p&gt;
&lt;p&gt;Redgate&amp;rsquo;s 2018 &lt;a href="https://www.red-gate.com/solutions/database-devops/report-2018"&gt;State of Database DevOps Report&lt;/a&gt; found that 67% of respondents use production data in development, test, or QA Environments, and that 58% of respondents reported that production data should be masked when in use in these environments:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you use production data in your dev, test, or QA environments?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;67% yes&lt;/li&gt;
&lt;li&gt;28% no&lt;/li&gt;
&lt;li&gt;5% not sure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Would your production data need to be modified or masked before use in dev, test, or QA environments?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;57% yes&lt;/li&gt;
&lt;li&gt;33% no&lt;/li&gt;
&lt;li&gt;10% not sure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are good reasons that production data is spread around like this: performance is extremely difficult to predict using data that doesn&amp;rsquo;t have a very similar distribution and similar size to production data.&lt;/p&gt;
&lt;p&gt;But after many years of working in IT, I know that most often this data is not modified or masked after being duplicated. These environments tend to be far less secure than production environments, and they are a very rich target for data breaches &amp;ndash; even if it&amp;rsquo;s not the developers themselves intentionally causing the data breach.&lt;/p&gt;
&lt;p&gt;The rise of malware and social attacks means that all environments in our company can the the source of a data breach.&lt;/p&gt;</description></item><item><title>Why You Should Take the State of Database DevOps Survey Today (Even If You Don't Do DevOps)</title><link>https://kendralittle.com/2018/11/27/why-you-should-take-the-state-of-database-devops-survey-today-even-if-you-dont-do-devops/</link><pubDate>Tue, 27 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/27/why-you-should-take-the-state-of-database-devops-survey-today-even-if-you-dont-do-devops/</guid><description>&lt;p&gt;When I began working with databases, nobody talked about DevOps. It was a few years before I heard the words &amp;lsquo;Agile&amp;rsquo; and &amp;lsquo;Extreme Programming&amp;rsquo;, (which I still read as &amp;ldquo;EXTREEEEEEMMMMME programmin!&amp;rdquo;). A lot has changed since then. But a lot &lt;strong&gt;hasn&amp;rsquo;t&lt;/strong&gt; changed as well.&lt;/p&gt;
&lt;p&gt;Please help us track the history of how we work with databases by &lt;a href="https://redgate.com/dbdsurvey"&gt;taking the Redgate State of Database DevOps survey today&lt;/a&gt;. I believe it&amp;rsquo;s helpful to our whole community to participate in this survey, and this post explains a few reasons why. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: The survey is now closed, thanks folks!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="the-survey-creates-a-history-of-how-we-manage-database-changes"&gt;The Survey Creates a History of How We Manage Database Changes&lt;/h2&gt;
&lt;p&gt;I was recently listening to a podcast on &lt;a href="https://go.forrester.com/what-it-means/ep76-future-of-it/"&gt;CIOs and the Future of IT&lt;/a&gt;. The hosts discussed that executives need to be very forward-thinking, and focus on where the company is going more than where the company &lt;strong&gt;is&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;One side effect of this: executives often think that their organization is ahead of where they actually are, in terms of changing processes and adapting to business initiatives.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Looking-ahead-and-perspective.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;This makes a lot of sense to me. When I learned to ride a motorcycle, the instructors emphasized that looking forward to where you are going is important when it comes to executing turns correctly. You need to have a wide field of vision and see obstacles, but if you stare at obstacles too much you are more likely to hit them. &lt;/p&gt;
&lt;p&gt;However, we need a feedback loop! We need all sorts of people who work with databases to discuss what actually happens. This allows Redgate to document and share what&amp;rsquo;s really happening right now in our technical patterns and practices. You can help us do that by answering the survey (and things like this are why we ask about your job title in the questions).&lt;/p&gt;
&lt;h2 id="responding-helps-us-identify-and-share-with-you-information-to-help-you-drive-change"&gt;Responding Helps Us Identify and Share with You Information to Help You Drive Change&lt;/h2&gt;
&lt;p&gt;Ever had an idea which would make a big difference for your organization, but you weren&amp;rsquo;t sure how to make it catch on?&lt;/p&gt;
&lt;p&gt;This might be an idea about DevOps, or it might be about data science, cloud adoption, general automation: any project big enough that it&amp;rsquo;s not simply something you can implement yourself.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s difficult as a DBA or developer to know how to approach these ideas. Do you need executive support? Is there another way you can help move it forward? The State of Database DevOps survey asks questions about how people have moved projects forward to help map out how change is instigated and sustained in companies.&lt;/p&gt;
&lt;p&gt;This helps Redgate discover and share with you how you can get projects moving (and you can apply this to projects other than DevOps).&lt;/p&gt;
&lt;h2 id="responding-provides-the-community-with-information-on-how-database-development-and-administration-jobs-are-changing"&gt;Responding Provides the Community with Information on How Database Development and Administration Jobs Are Changing&lt;/h2&gt;
&lt;p&gt;I hear from a lot of folks who are concerned about the future. There&amp;rsquo;s so much to learn, and it&amp;rsquo;s increasingly difficult to prioritize between learning more about the tasks you work on today, and learning more about the tools which you may use tomorrow. &lt;/p&gt;
&lt;p&gt;The results from the State of Database DevOps help show the community: how are roles changing? What&amp;rsquo;s still the same? This will help you answer those tough questions about what to focus on.&lt;/p&gt;
&lt;h2 id="take-the-survey-today"&gt;Take the Survey Today!&lt;/h2&gt;
&lt;p&gt;Please share the survey with your colleagues (shortlink: &lt;a href="http://redgate.com/DBDSurvey"&gt;redgate.com/DBDSurvey&lt;/a&gt;). And remember, the survey is only open until November 30th, so &lt;a href="https://redgate.com/dbdsurvey"&gt;complete the survey today&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How to Create Dynamic Agenda Slides with PowerPoint Zoom</title><link>https://kendralittle.com/2018/11/26/how-to-create-dynamic-agenda-slides-with-powerpoint-zoom/</link><pubDate>Mon, 26 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/26/how-to-create-dynamic-agenda-slides-with-powerpoint-zoom/</guid><description>&lt;p&gt;I&amp;rsquo;ve become a PowerPoint fan for a couple of reasons. First, I&amp;rsquo;ve gotten fairly proficient with PowerPoint, so I can put together presentations quickly and my slides carry greater impact. Also, the PowerPoint team has added features that I believe help me deliver presentations more effectively.&lt;/p&gt;
&lt;p&gt;This describes one of those features: the new &amp;lsquo;Zoom&amp;rsquo; functionality.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Create-dynamic-agenda-slides-with-PowerPoint-Zoom-350-x-350.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="zoom-is-about-dynamic-presentations"&gt;&amp;lsquo;Zoom&amp;rsquo; Is About Dynamic Presentations&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s important to give your audience context for where you are in a presentation &amp;ndash; especially in a talk longer than 5 minutes. I like to give folks an outline of the narrative at the beginning of the talk in the agenda. While I&amp;rsquo;m going through the material, I like to return to that agenda and show where we are in the talk.&lt;/p&gt;
&lt;p&gt;This has more than one benefit: first and foremost, it helps keep your audience from being too restless, because they understand more how much you&amp;rsquo;re going to cover. But additionally, I find that it helps solidify learning for your audience by repeatedly contextualizing details within the larger narrative structure. In other words, revisiting an agenda effectively can help prevent &amp;ldquo;not seeing the forest for the trees.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;For years, I&amp;rsquo;ve built slides manually that do this &amp;ndash; but as you add and remove sections from your talk, it becomes a real pain to update. The &amp;lsquo;Zoom&amp;rsquo; feature makes it much easier to build a dynamic agenda, and it&amp;rsquo;s more powerful than manually created slides can be, too.&lt;/p&gt;
&lt;h2 id="its-easier-to-show-this-than-it-is-to-describe-it-so-heres-a-15-minute-video-showing-what-it-looks-like"&gt;It&amp;rsquo;s Easier to Show This Than It Is to Describe It, So Here&amp;rsquo;s a 1.5 Minute Video Showing What It Looks Like&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/G1XqbXPr9lk?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="sorry-this-isnt-available-in-every-installation-of-powerpoint"&gt;Sorry, This Isn&amp;rsquo;t Available in Every Installation of PowerPoint&lt;/h2&gt;
&lt;p&gt;As of the time of this writing, Zoom is available in PowerPoint for Office 365, PowerPoint for Office 365 for Mac, and PowerPoint 2019. The documentation from Microsoft is &lt;a href="https://support.office.com/en-us/article/use-zoom-for-powerpoint-to-bring-your-presentation-to-life-9d6c58cd-2125-4d29-86b1-0097c7dc47d7"&gt;here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Join Me for an Upcoming Webinar on Data Masking: Insights and Actions</title><link>https://kendralittle.com/2018/11/21/join-me-for-an-upcoming-webinar-data-masking-insights-actions/</link><pubDate>Wed, 21 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/21/join-me-for-an-upcoming-webinar-data-masking-insights-actions/</guid><description>&lt;p&gt;&lt;a href="https://attendee.gotowebinar.com/register/2217637282347027971?source=KB"&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Data-Masking-Webinar-Kendra-1024x538.png"&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Click the image to register for the webcast&lt;/p&gt;
&lt;h2 id="there-has-never-been-a-better-time-to-start-a-project-to-champion-data-privacy"&gt;There Has Never Been a Better Time to Start a Project to Champion Data Privacy&lt;/h2&gt;
&lt;p&gt;In &lt;a href="https://stripe.com/files/reports/the-developer-coefficient.pdf"&gt;a recent Harris poll sponsored by the payment company Stripe&lt;/a&gt;, over 1,000 C-level executives were asked to rate which factors they feel are most threatening to their business.&lt;/p&gt;
&lt;p&gt;The #1 item that executives rated as &amp;ldquo;somewhat&amp;rdquo; or &amp;ldquo;very&amp;rdquo; threatening to the success of their business is &lt;strong&gt;security / data breaches&lt;/strong&gt;. The #2 rated threat to these businesses? &lt;strong&gt;Increased regulation&lt;/strong&gt;. &lt;/p&gt;
&lt;h2 id="data-masking-mitigates-these-top-threats"&gt;Data Masking Mitigates These Top Threats&lt;/h2&gt;
&lt;p&gt;One of my very first jobs when I began in IT was to build out environments for developer and test teams at a software development company. At first, we didn&amp;rsquo;t mask any of this data. After problems arose, we began masking only a single field. That was a huge mistake.&lt;/p&gt;
&lt;p&gt;In this &lt;a href="https://attendee.gotowebinar.com/register/2217637282347027971?source=KB"&gt;upcoming free webcast&lt;/a&gt;, I&amp;rsquo;ll share the following in just 30 minutes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why data professionals have a history of neglecting privacy (just like I did in that first job)&lt;/li&gt;
&lt;li&gt;The three industry drivers for data masking&lt;/li&gt;
&lt;li&gt;Why regulations have become a top risk to C-level executives&lt;/li&gt;
&lt;li&gt;Key elements of static data masking tools to consider when evaluating products&lt;/li&gt;
&lt;li&gt;Pains that people run into when implementing data masking (and how Redgate tools address those pains)&lt;/li&gt;
&lt;li&gt;An overview of the data masking process&lt;/li&gt;
&lt;li&gt;Next steps to take in making a case for a data masking project at your organization&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="now-is-the-time-to-become-a-privacy-champion"&gt;Now Is the Time to Become a Privacy Champion&lt;/h2&gt;
&lt;p&gt;Whether or not you are an IT leader, a developer, or a DBA, right now you have a huge opportunity to make a difference for your organization,  your customers, and your own career by championing privacy.&lt;/p&gt;
&lt;p&gt;Yep, your own career! Those top two C-level concerns mentioned at the beginning of this post means that initiating projects like data masking and seeing them through from proof-of-concept to implementation is a big resume-building career move. That&amp;rsquo;s true whether you choose a Redgate solution, or use the information in this webinar to go a different route. &lt;/p&gt;
&lt;p&gt;Join me in this upcoming webinar to learn the initial steps that you can make to instigate changes in your company: and to help mitigate the top risks that are keeping C-level executives up at night.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://attendee.gotowebinar.com/register/2217637282347027971?source=KB"&gt;Register&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Watch: Getting Executive Buy-In for DevOps: 3 Top Tips (video)</title><link>https://kendralittle.com/2018/11/19/watch-getting-executive-buy-in-for-devops-3-top-tips-video/</link><pubDate>Mon, 19 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/19/watch-getting-executive-buy-in-for-devops-3-top-tips-video/</guid><description>&lt;p&gt;High DevOps performers report greater workplace satisfaction than their peers. But implementing DevOps isn’t a matter of being great at writing code: to become a high DevOps performer, you need the powerful catalyst of executive support.&lt;/p&gt;
&lt;h2 id="communicating-the-value-of-devops-to-company-leaders-requires-changing-your-perspective"&gt;Communicating the Value of DevOps to Company Leaders Requires Changing Your Perspective&lt;/h2&gt;
&lt;p&gt;In this webinar, I discuss the value of DevOps from the perspectives of CEOs, CIOs/CTOs, and Managers. We explore how the role of CIOs and CTOs are undergoing a major transformation, and how DevOps aligns with that transformation.&lt;/p&gt;
&lt;p&gt;You will discover a fresh take on how to discuss DevOps with company leaders, and an understanding of how to explain the value of DevOps to people in these roles.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/tlmCh62_Xts?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Fix My Functions: Speeding Up Scalar and Table Valued UDFs (video)</title><link>https://kendralittle.com/2018/11/14/fix-my-functions-speeding-up-scalar-and-table-valued-udfs-video/</link><pubDate>Wed, 14 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/14/fix-my-functions-speeding-up-scalar-and-table-valued-udfs-video/</guid><description>&lt;p&gt;Last week, I presented on the topic of TSQL User Defined Functions (UDFs) in SQL Server at the PASS Summit.&lt;/p&gt;
&lt;h2 id="video-1-hour-10-minutes"&gt;Video (1 hour 10 minutes)&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Scalar UDF inlining&lt;/strong&gt;: If you're just here to see the SQL Server 2019 (CTP2.1+) scalar UDF inlining, that starts 54 minutes into the video.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/HuBCyjxFAqM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>PASS Summit 2018 - Day 1 Keynote Announcements</title><link>https://kendralittle.com/2018/11/07/pass-summit-2018-day-1-keynote-announcements/</link><pubDate>Wed, 07 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/07/pass-summit-2018-day-1-keynote-announcements/</guid><description>&lt;p&gt;Good morning from Seattle, at the Summit for the Professional Association of SQL Server.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m lucky enough to be sitting at the blogger table this morning, watching the keynote of announcements.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Kendra-Bob-and-Brent-at-the-Blogger-Table-300x225.jpg" width="230"&gt;
&lt;/figure&gt;
I&amp;rsquo;m following along with the keynote and making notes on slides, and I&amp;rsquo;ll share those slides with you below.&lt;/p&gt;
&lt;h2 id="dont-feel-like-reading-or-rewatching-the-presentation"&gt;Don&amp;rsquo;t Feel Like Reading or Rewatching the Presentation?&lt;/h2&gt;
&lt;p&gt;Join me on Tuesday, Nov 20th, with Grant Fritchey and Steve Jones in a webcast to sum up everything we learned at PASS Summit!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://register.gotowebinar.com/register/4225546725293674755?source=KB"&gt;Register&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="keynote-summary-in-slides"&gt;Keynote Summary in Slides&lt;/h2&gt;
&lt;iframe src="//www.slideshare.net/slideshow/embed_code/key/y76UMzJfa748iy" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="//www.slideshare.net/KendraLittle2/sql-pass-summit-2018" title="SQL PASS Summit 2018"&gt;SQL PASS Summit 2018&lt;/a&gt;&lt;/strong&gt; from &lt;strong&gt;&lt;a href="https://www.slideshare.net/KendraLittle2"&gt;KendraLittle2&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="text-from-the-slides"&gt;Text from the Slides&lt;/h2&gt;
&lt;p&gt;PASSION award winner: Michael Johnson&lt;/p&gt;
&lt;h3 id="rohan-kumar"&gt;Rohan Kumar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Hybrid cloud is the true enabler for digital transformation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AI is helping MS customers&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand their customers and better meet their needs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improve their operations&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Critical to build training model on data that spans the hybrid estate&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CTP 2.1 has been released&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monthly releases&lt;/li&gt;
&lt;li&gt;Using Azure to get feedback on a constant basis&lt;/li&gt;
&lt;li&gt;Request for engagement from you&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="conor-cunningham-and-bob-ward"&gt;Conor Cunningham and Bob Ward&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Demo: Removing page latch waits in tempdb&lt;/li&gt;
&lt;li&gt;Behind the scenes, it’s using Hekaton in system tables in tempdb to speed this up&lt;/li&gt;
&lt;li&gt;Not yet in preview&lt;/li&gt;
&lt;li&gt;Will be in SQL Server 2019&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="asad-and-nellie"&gt;Asad and Nellie&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Demonstrating Azure Data Studio and Data Clusters&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use Python and Notebooks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Can query HDFS using native features in SQL Server engine to read that data&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Access multiple data sources through SQL Server&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="more-from-rohan-kumar"&gt;More from Rohan Kumar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Azure Database Migration Service&lt;/li&gt;
&lt;li&gt;Near zero downtime&lt;/li&gt;
&lt;li&gt;Migrate at scale&lt;/li&gt;
&lt;li&gt;Optimize IT Infrastructure&lt;/li&gt;
&lt;li&gt;Azure SQL Database: 5 million active at any given time, a petabyte of telemetry data every day&lt;/li&gt;
&lt;li&gt;Microsoft is using machine learning against the data&lt;/li&gt;
&lt;li&gt;Managed Instances&lt;/li&gt;
&lt;li&gt;Big push to get customers here&lt;/li&gt;
&lt;li&gt;General Availability of Business Critical SKU starting December 1&lt;/li&gt;
&lt;li&gt;Azure SQL Database Hyperscale&lt;/li&gt;
&lt;li&gt;4 TB limit on initial implementation&lt;/li&gt;
&lt;li&gt;Have been working on rearchitecting&lt;/li&gt;
&lt;li&gt;Scales out storage over various nodes&lt;/li&gt;
&lt;li&gt;Has abilities for fast point in time restore&lt;/li&gt;
&lt;li&gt;Scale storage and compute independently&lt;/li&gt;
&lt;li&gt;Accelerated DB Recovery &amp;amp; Machine Learning Services&lt;/li&gt;
&lt;li&gt;Azure SQL Database&lt;/li&gt;
&lt;li&gt;Goal is to make sure that no matter what happens, recovery happens in “constant time”&lt;/li&gt;
&lt;li&gt;Machine Learning workloads in Azure SQL Database – enables migration for these features&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="lindsey-allen"&gt;Lindsey Allen&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We don’t have fancy machines&lt;/li&gt;
&lt;li&gt;We have 2 socket machines&lt;/li&gt;
&lt;li&gt;Most customers don’t like figuring out sharding with partitioning keys – whatever key you choose is wrong&lt;/li&gt;
&lt;li&gt;This is going to happen automatically behind the scenes&lt;/li&gt;
&lt;li&gt;Now they take snapshots and restore from those – not a size of data operation&lt;/li&gt;
&lt;li&gt;Accelerated Database Recovery&lt;/li&gt;
&lt;li&gt;How long will it take to restore?&lt;/li&gt;
&lt;li&gt;Painful for customers&lt;/li&gt;
&lt;li&gt;Painful in Azure as well&lt;/li&gt;
&lt;li&gt;Can aggressively truncate the log – even in full recovery mode&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/sql-database/sql-database-accelerated-database-recovery"&gt;https://docs.microsoft.com/en-us/azure/sql-database/sql-database-accelerated-database-recovery&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="deborah-chen"&gt;Deborah Chen&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Multi-Master Replication in CosmosDB&lt;/li&gt;
&lt;li&gt;Azure Cosmos DB&lt;/li&gt;
&lt;li&gt;Apps can read from any region and write to them as well&lt;/li&gt;
&lt;li&gt;Drawing app&lt;/li&gt;
&lt;li&gt;Data being replicated to Japan in almost real time&lt;/li&gt;
&lt;li&gt;Go to instance in Japan and draw, and it appears&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="john-macintyre"&gt;John Macintyre&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SQL Data Warehouse competing&lt;/li&gt;
&lt;li&gt;30% less expensive than Amazon Redshift&lt;/li&gt;
&lt;li&gt;Fastest cloud DW based on benchmarks&lt;/li&gt;
&lt;li&gt;Demo with 6 trillion rows of data&lt;/li&gt;
&lt;li&gt;TPC-H Benchmark running&lt;/li&gt;
&lt;li&gt;Processing over a trillion rows a second&lt;/li&gt;
&lt;li&gt;Demo: prioritizing workloads in SQL Data Warehouse&lt;/li&gt;
&lt;li&gt;Demonstration of queries being queued, waiting for system resources on a busy system&lt;/li&gt;
&lt;li&gt;Connect to a dashboard using a special service account&lt;/li&gt;
&lt;li&gt;That work gets prioritized and jumps the queue&lt;/li&gt;
&lt;li&gt;Feature name: workload management&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ariel-pisetzky-of-taboola"&gt;Ariel Pisetzky of Taboola&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Azure Data Explorer&lt;/li&gt;
&lt;li&gt;Used across Microsoft internally for several years to explore logs and do analysis&lt;/li&gt;
&lt;li&gt;Ingest unstructured and semi-structured data&lt;/li&gt;
&lt;li&gt;Not a lot of prep work to do quick queries&lt;/li&gt;
&lt;li&gt;Demo: exploring data&lt;/li&gt;
&lt;li&gt;Can query and show results in graphs or tables&lt;/li&gt;
&lt;li&gt;Using the tool to report on the customer experience&lt;/li&gt;
&lt;li&gt;“What is the 5% of the slowest recommendations we provide?”&lt;/li&gt;
&lt;li&gt;• Identify spikes where they are above 800 ms&lt;/li&gt;
&lt;li&gt;• Using queries to zoom in and identify who is impacted&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="patrick-leblanc"&gt;Patrick LeBlanc&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dataflows&lt;/li&gt;
&lt;li&gt;Point Power BI to any data lake store&lt;/li&gt;
&lt;li&gt;It will figure out connectivity and transformations for the scenario&lt;/li&gt;
&lt;li&gt;Big customer request&lt;/li&gt;
&lt;li&gt;“Self-service for big data” stored in the data lake&lt;/li&gt;
&lt;li&gt;SSRS Reports in Power BI&lt;/li&gt;
&lt;li&gt;Reporting Services – things went quiet for a long time&lt;/li&gt;
&lt;li&gt;BUT NOW WE HAVE MORE&lt;/li&gt;
&lt;li&gt;Paginated reports in Power BI Service&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="deepsha-menghani"&gt;Deepsha Menghani&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Demo: Shell health &amp;amp; safety portal&lt;/li&gt;
&lt;li&gt;Predictive alert&lt;/li&gt;
&lt;li&gt;Azure database notebook&lt;/li&gt;
&lt;li&gt;Need to have data to feed and train – and you can’t just burn down a gas station – she checked&lt;/li&gt;
&lt;li&gt;Can do a keyword centric search for images to feed into the model&lt;/li&gt;
&lt;li&gt;Image classification – databricks lets you build on existing models&lt;/li&gt;
&lt;li&gt;Live demo: image detection&lt;/li&gt;
&lt;li&gt;Hold a cigarette in front of a camera&lt;/li&gt;
&lt;li&gt;Image identified and detected&lt;/li&gt;
&lt;li&gt;Notification suggesting stopping a pump&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="and-were-done-goodbye-from-rohan"&gt;And We’re Done! Goodbye from Rohan&lt;/h3&gt;</description></item><item><title>Register for My Upcoming Session on Digital Transformation</title><link>https://kendralittle.com/2018/11/02/register-for-my-upcoming-session-on-digital-transformation/</link><pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/02/register-for-my-upcoming-session-on-digital-transformation/</guid><description>&lt;p&gt;I&amp;rsquo;m excited to have a session accepted to &lt;a href="https://groupby.org/"&gt;GroupBy&lt;/a&gt;, a free online conference targeting the Microsoft data platform community. The conference is sponsored by &lt;a href="https://www.brentozar.com/"&gt;Brent Ozar Unlimited&lt;/a&gt;, and sessions are chosen by community votes. &lt;/p&gt;
&lt;p&gt;My session will be given on Fri, Dec 21, along with five other terrific looking sessions. You should  &lt;a href="https://register.gotowebinar.com/register/7245403788522473995"&gt;register for GroupBy&lt;/a&gt; here.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Digital-Transformation-1.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="about-my-session"&gt;About My Session&lt;/h2&gt;
&lt;p&gt;My session is &lt;strong&gt;&amp;ldquo;What ‘Digital Transformation’ means, and how you can use it to advance your career (without being a robot).&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the abstract:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Whether you love or hate buzzwords, the big ones signify critical cultural changes. In this session, Kendra Little will explain what executives mean when they describe a ‘digital transformation’, why this transformation is happening across all industries, and how understanding this gives developers and database administrators an advantage in building their careers.&lt;/p&gt;
&lt;p&gt;You will learn what motivates CEOs to modify their business models in a digital transformation, and patterns and anti-patterns of companies that have attempted these transformations – with different results.&lt;/p&gt;
&lt;p&gt;You’ll leave the session with an understanding of the core ideas and philosophies behind digital transformation that will help you prioritize what to learn, guide your interactions at work, and strategize your career path.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://groupby.org/conference-session-abstracts/what-digital-transformation-means-and-how-you-can-use-it-to-advance-your-career/"&gt;Group By session abstract&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="i-wasnt-sure-that-this-session-would-get-votes"&gt;I Wasn&amp;rsquo;t Sure That This Session Would Get Votes&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m particularly excited that the community of voters saw value in this topic because I haven&amp;rsquo;t seen any talks on this topic before in the data platform community. &lt;/p&gt;
&lt;p&gt;While we hear the phrase &amp;lsquo;digital transformation&amp;rsquo; in conference keynotes frequently these days, I think many technologists don&amp;rsquo;t think much about what it means. Or worse, assume it doesn&amp;rsquo;t mean &lt;em&gt;anything&lt;/em&gt;. &lt;/p&gt;
&lt;h2 id="digital-transformation-is-meaningful-and-is-absolutely-worth-understanding"&gt;&amp;lsquo;Digital Transformation&amp;rsquo; Is Meaningful, and Is Absolutely Worth Understanding&lt;/h2&gt;
&lt;p&gt;For the last several months, I have been researching what worries and inspires CEOs and CIOs. I was surprised to find a large body of studies and predictions of massive trends in “digital transformation” across all industries.&lt;/p&gt;
&lt;p&gt;What I once thought was “just a buzzword” is a shorthand that executives use to represent major changes in business models. It&amp;rsquo;s incredibly useful for practitioners, team leads, and managers to understand what the goals of a digital transformation are and how success is measured. This understanding helps you communicate better with executives, align your team&amp;rsquo;s work with business strategies, and ask for the right resources and headcount to execute on critical tasks for your organization.&lt;/p&gt;
&lt;p&gt;I hope you join me in December at GroupBy!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://register.gotowebinar.com/register/7245403788522473995"&gt;Register for GroupBy&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Watch: The Single Question to Predict Success for DevOps (31 Minutes)</title><link>https://kendralittle.com/2018/11/02/watch-the-single-question-to-predict-success-for-devops-31-minutes/</link><pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/11/02/watch-the-single-question-to-predict-success-for-devops-31-minutes/</guid><description>&lt;p&gt;What if you could assess the performance level of your team by asking one simple question? In his recent webinar with &lt;a href="https://www.red-gate.com/"&gt;Redgate&lt;/a&gt;, Gene Kim (&lt;a href="https://twitter.com/RealGeneKim"&gt;@realgenekim&lt;/a&gt;) suggests that you can.&lt;/p&gt;
&lt;p&gt;In this 30 minute session, I discuss three insights from the recent &amp;lsquo;Gene Kim joins Redgate to discuss The 2018 Accelerate State of DevOps Report&amp;rsquo; webinar &lt;a href="https://www.youtube.com/watch?v=is43drdJSXo"&gt;recording&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also dig into why these insights make a compelling argument for modifying your organization&amp;rsquo;s change control process.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/l5fN0IKXFCY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="key-insights-from-gene-kim"&gt;Key Insights from Gene Kim&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;The question, &amp;ldquo;To what degree do we fear doing deployments?&amp;rdquo; on a scale of 1 to 7, is a simple way to measure whether or not your company is a high performer&lt;/li&gt;
&lt;li&gt;Although database operations has been a high-spend area for a long time, it has been comparatively impoverished in most organizations when it comes to tooling and automation, as compared to other areas of Software Development&lt;/li&gt;
&lt;li&gt;Becoming a high performer at DevOps includes completely rethinking how change control is managed for your IT organization&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Interviewing for Your First Tech Job - Slides</title><link>https://kendralittle.com/2018/10/08/interviewing-for-your-first-tech-job-slides/</link><pubDate>Mon, 08 Oct 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/10/08/interviewing-for-your-first-tech-job-slides/</guid><description>&lt;p&gt;I was lucky to get an opportunity to present a session to some college students at Seminole State College in Florida last week.&lt;/p&gt;
&lt;h2 id="about-the-event"&gt;About the Event&lt;/h2&gt;
&lt;p&gt;I was in town for SQL Saturday Orlando&amp;ndash; a fantastic event on its own. The organizers run a simultaneous seminar for students at the college studying software development and IT topics, and it&amp;rsquo;s an opportunity where they can hear from professionals in IT professions. I gave a session on interviewing best practices.&lt;/p&gt;
&lt;h2 id="slides"&gt;Slides&lt;/h2&gt;
&lt;p&gt;The students were a terrific audience, and I really enjoyed speaking. The slides I shared that day are here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/LitKnd/littlekendracomments/blob/main/PDFs/Interviewing/Interviewing-for-your-first-tech-job.pdf"&gt;Interviewing for your first tech job&lt;/a&gt;&lt;/p&gt;</description></item><item><title>DevOps Terms - and Why They Matter to Database Specialists</title><link>https://kendralittle.com/2018/10/04/devops-terms-and-why-they-matter-to-database-specialists/</link><pubDate>Thu, 04 Oct 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/10/04/devops-terms-and-why-they-matter-to-database-specialists/</guid><description>&lt;h2 id="about-this-session"&gt;About This Session&lt;/h2&gt;
&lt;p&gt;In this 20 minute session, I define scrum, continuous deployment, test driven development, DevOps, and related concepts.&lt;/p&gt;
&lt;p&gt;I close with a quick discussion of why Database Administrators and Developers should care about DevOps.&lt;/p&gt;
&lt;h2 id="subscribe"&gt;Subscribe&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Subscribe&lt;/strong&gt;: &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;Subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/sfj-_Astg9Q?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>SQL Change Automation, Visual Studio, and the Unknown SQL Server Platform Error</title><link>https://kendralittle.com/2018/10/03/sql-change-automation-visual-studio-and-the-unknown-sql-server-platform-error/</link><pubDate>Wed, 03 Oct 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/10/03/sql-change-automation-visual-studio-and-the-unknown-sql-server-platform-error/</guid><description>&lt;p&gt;I recently set up Redgate&amp;rsquo;s &lt;a href="https://www.red-gate.com/products/sql-development/sql-change-automation/index"&gt;SQL Change Automation&lt;/a&gt; in Visual Studio 2017, and I ran into a confusing error when I started trying to use it. For any other folks out there searching on &amp;ldquo;Unknown SQL Server Platform,&amp;rdquo; here&amp;rsquo;s how I got past it.&lt;/p&gt;
&lt;p&gt;Spoiler: Visual Studio suggested updating Microsoft&amp;rsquo;s SQL Server Data Tools, which failed for me and wasted a lot of time. Updating Visual Studio &lt;strong&gt;did&lt;/strong&gt; fix my issue.&lt;/p&gt;
&lt;h2 id="the-basics-on-my-setup"&gt;The Basics on My Setup&lt;/h2&gt;
&lt;p&gt;When I installed Visual Studio 2017, I selected the &amp;lsquo;Data storage and processing&amp;rsquo; workload, which contains SQL Server Data tools as well as some of the Redgate tools:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/visual-studio-2017-workloads-installation.png"
alt="Image of visual studio 2017 workload options at install time"&gt;
&lt;/figure&gt;
&lt;p&gt;Visual Studio 2017 workloads&lt;/p&gt;
&lt;p&gt;I used the default checkboxes on the right there, installing everything except F# desktop language support.&lt;/p&gt;
&lt;h2 id="first-i-created-a-new-project"&gt;First, I Created a New Project&lt;/h2&gt;
&lt;p&gt;In the &amp;lsquo;SQL Change Automation&amp;rsquo; window, I clicked &amp;lsquo;Create Project&amp;rsquo;, selected &amp;lsquo;SQL Change Automation Project&amp;rsquo; and gave it a name, and click OK. This launched the wizard to set up the project.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/get-started.png"&gt;
&lt;/figure&gt;
&lt;p&gt;I clicked &amp;lsquo;Get Started&amp;rsquo;, and proceeded to the step to configure my connections.&lt;/p&gt;
&lt;p&gt;At this point, I was prompted to specify my development database and deployment target. I chose two databases on my local SQL Server 2017 instance.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/database-selection-sql-change-automation-setup.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Configured instances&lt;/p&gt;
&lt;p&gt;I clicked &amp;lsquo;Next&amp;rsquo;, and that&amp;rsquo;s where things got wacky.&lt;/p&gt;
&lt;h2 id="unknown-sql-server-platform---the-target-platform-for-this-project-is-not-supported-by-the-installed-sql-server-tools"&gt;Unknown SQL Server Platform - the Target Platform for This Project Is Not Supported by the Installed SQL Server Tools.&lt;/h2&gt;
&lt;p&gt;When I proceeded past this point and had SQL Change Automation create my baseline, it stopped pretty quickly and I saw a message&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Unknown-SQL-Server-Platform-Target-Platform-Not-Supported.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Wat???&lt;/p&gt;
&lt;p&gt;When I clicked on the blue link, I was taken to a download for the most recent version of Microsoft&amp;rsquo;s &lt;a href="https://docs.microsoft.com/en-us/sql/ssdt/download-sql-server-data-tools-ssdt"&gt;SQL Server Data Tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After I carefully read the page and made sure I didn&amp;rsquo;t have Visual Studio extensions installed that would cause a problem, I attempted to update the SQL Server Data Tools and found that installation ran for 7-10 minutes, then failed with an &amp;ldquo;incorrect function&amp;rdquo; error.&lt;/p&gt;
&lt;p&gt;I restarted Windows. I tried updating again. Same failure.&lt;/p&gt;
&lt;h2 id="what-fixed-this-for-me-updating-visual-studio"&gt;What Fixed This for Me: Updating Visual Studio&lt;/h2&gt;
&lt;p&gt;I went into the &amp;lsquo;Help&amp;rsquo; menu in Visual Studio to capture the version numbers of my extensions (that&amp;rsquo;s under Help -&amp;gt; About Microsoft Visual Studio), and that&amp;rsquo;s when I realized: I should probably update Visual Studio before I wasted any more time chasing this error.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/visual-studio-check-for-updates.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Updates, please!&lt;/p&gt;
&lt;p&gt;After I opened &amp;ldquo;Check for Updates,&amp;rdquo; I saw that there was a bunch of stuff that Visual Studio wanted to fix. I told it to apply those changes (it really wasn&amp;rsquo;t clear what the changes were, I just let it run), and then&amp;hellip;.&lt;/p&gt;
&lt;h2 id="everything-worked-after-that"&gt;Everything Worked After That&lt;/h2&gt;
&lt;p&gt;Yep, everything was fine. I still had the exact same version of SQL Server Data Tools as before (15.1.61808.07020, for the record), but Visual Studio was now happy to use it, for whatever reason.&lt;/p&gt;
&lt;p&gt;I was able to complete my baseline and get on with my day.&lt;/p&gt;
&lt;h2 id="i-should-really-know-better"&gt;I Should Really Know Better&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Microsoft has changed a lot in the last few years, but one truth that remains eternal is &amp;ldquo;always check for patches before you start to use a fresh install.&amp;rdquo;&lt;/p&gt;</description></item><item><title>I Helped Write a Book! No, Not THOSE Books...</title><link>https://kendralittle.com/2018/10/01/i-helped-write-a-book-no-not-those-books/</link><pubDate>Mon, 01 Oct 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/10/01/i-helped-write-a-book-no-not-those-books/</guid><description>&lt;p&gt;Every now and again, someone asks if I write romance novels.&lt;/p&gt;
&lt;p&gt;Why? Well, let&amp;rsquo;s ask Bing who Kendra Little is&amp;hellip;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/the-many-faces-of-kendra-little.png"&gt;
&lt;/figure&gt;
&lt;p&gt;To clarify,  I am not married, I have dogs instead of children, and I prefer romances about strong women who bring SQL Servers to their knees.&lt;/p&gt;
&lt;p&gt;I also don&amp;rsquo;t think it&amp;rsquo;s possible to drink too much coffee.&lt;/p&gt;
&lt;p&gt;Most of those pictures are of me, but a careful reader will note that the biography at the top references a domain name that, sadly, dear reader, I do &lt;em&gt;not&lt;/em&gt; own. Someone out there named Kendra Little gets sweet royalties from her contemporary romance novels, but they don&amp;rsquo;t come to this address.&lt;/p&gt;
&lt;h2 id="i-helped-malathi-mahadevan-write-a-different-kind-of-book"&gt;I Helped Malathi Mahadevan Write a Different Kind of Book&lt;/h2&gt;
&lt;p&gt;&amp;lsquo;Data Professionals at Work&amp;rsquo; is a new book by &lt;a href="https://twitter.com/sqlmal?lang=en"&gt;Malathi Mahadevan&lt;/a&gt;. Mala went out and interviewed loads of data professionals, and talked with us about topics like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Data-Professionals-at-Work-Book.jpg"&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;How to stand out as a data professional&lt;/li&gt;
&lt;li&gt;How to focus on the right things and evolve your career in a fast-changing world&lt;/li&gt;
&lt;li&gt;How to understand current trends and best practices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mala interviewed an amazing group of people, including &lt;br&gt;
Mindy Curnutt, Julie Smith, Kenneth Fisher, Andy Leonard, Jes Borland, Kevin Feasel, Ginger Grant, Vicky Harp, Kendra Little (THIS Kendra, right here), Jason Brimhall, Tim Costello, Andy Mallon, Steph Locke, Jonathan Stewart, Joseph Sack, John Q. Martin, John Morehouse, Kathi Kellenberger, Argenis Fernandez, Kirsten Benzel, Tracy Boggiano, Dave Walden, Matt Gordon, Jimmy May, Drew Furgiuele, Marlon Ribunal, and Joseph Fleming.&lt;/p&gt;
&lt;p&gt;Here is a twitter list with all those awesome folks: &lt;a href="https://twitter.com/Kendra_Little/lists/data-pros-at-work/members"&gt;https://twitter.com/Kendra_Little/lists/data-pros-at-work/members&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="heres-where-you-can-buy-the-book"&gt;Here&amp;rsquo;s Where You Can Buy the Book&lt;/h2&gt;
&lt;p&gt;Data Professionals at work is &lt;em&gt;way better than a bodice-ripper&lt;/em&gt; and is currently &lt;a href="http://a.co/d/9OqEMbS"&gt;available for pre-order at Amazon.com in softcover&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also compare prices on the &lt;a href="https://www.apress.com/us/book/9781484239667"&gt;Apress site here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t promise that my chapter is steamy, but I hope that you enjoy it.&lt;/p&gt;</description></item><item><title>Help Me Present at GroupBy: Review My Abstract</title><link>https://kendralittle.com/2018/09/27/help-me-present-at-groupby-review-my-abstract/</link><pubDate>Thu, 27 Sep 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/09/27/help-me-present-at-groupby-review-my-abstract/</guid><description>&lt;h2 id="about-my-session-proposal"&gt;About My Session Proposal&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve submitted a session proposal to the free, online GroupBy conference. Voting will open for sessions soon, but before then, you can help me out by reading my abstract. Is it a session you&amp;rsquo;d like to see?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Digital-Transformation.jpg" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="help-me-improve-it"&gt;Help Me Improve It&lt;/h2&gt;
&lt;p&gt;Got any constructive criticism that you think would make the session or abstract better? Let me know in the comments over on the abstract for &amp;ldquo;&lt;a href="https://groupby.org/conference-session-abstracts/what-digital-transformation-means-and-how-you-can-use-it-to-advance-your-career/"&gt;What &amp;lsquo;Digital Transformation&amp;rsquo; Means, and How You Can Use It to Advance Your Career (Without Being a Robot)&lt;/a&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://groupby.org/conference-session-abstracts/what-digital-transformation-means-and-how-you-can-use-it-to-advance-your-career/"&gt;Review me!&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Four Free Sessions in October</title><link>https://kendralittle.com/2018/09/26/new-live-sessions-on-devops/</link><pubDate>Wed, 26 Sep 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/09/26/new-live-sessions-on-devops/</guid><description>&lt;p&gt;I&amp;rsquo;ve got FOUR sessions coming up in October.  These sessions will each be 30 minutes.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/New-Sessions.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="redgate-sessions"&gt;Redgate Sessions&lt;/h2&gt;
&lt;p&gt;Wed, Oct 3, 9AM PT / 12PM ET: &lt;br&gt;
&lt;strong&gt;How to Lead DBAs to Embrace DevOps, Rather than Fear Change&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tues Oct 30, 9AM PT / 12PM ET:&lt;br&gt;
&lt;strong&gt;The Single Question to Predict Success for DevOps, and What It Means for Change Control&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="dear-sql-dba-sessions"&gt;Dear SQL DBA Sessions&lt;/h2&gt;
&lt;p&gt;Tues Oct 2, 9AM PT / 12PM ET:&lt;br&gt;
&lt;strong&gt;DevOps Terms and Why they Matter for Database Specialists&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tues Oct 23, 9AM PT/ 12PM ET:&lt;br&gt;
&lt;strong&gt;Book Review, &amp;ldquo;Accelerate: The Science of Lean Software and DevOps&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Registration for these events has now closed.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Why I Love DML Triggers in SQL Server</title><link>https://kendralittle.com/2018/09/11/why-i-love-dml-triggers-in-sql-server/</link><pubDate>Tue, 11 Sep 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/09/11/why-i-love-dml-triggers-in-sql-server/</guid><description>&lt;p&gt;It&amp;rsquo;s &lt;a href="https://voiceofthedba.com/2018/09/03/t-sql-tuesday-106-trigger-headaches-or-happiness/"&gt;TSQL Tuesday!&lt;/a&gt; If you&amp;rsquo;re not familiar, TSQL Tuesday is a monthly blogging event where a Microsoft Data Platform community member chooses a writing prompt. This is a great thing if you&amp;rsquo;re interested in starting a technical blog and wonder, &amp;ldquo;What would I write about?&amp;rdquo; It&amp;rsquo;s also great if, like me, you occasionally want a little outside inspiration to shake things up.&lt;/p&gt;
&lt;p&gt;This month&amp;rsquo;s topic is from Steve Jones: we&amp;rsquo;re &lt;a href="https://voiceofthedba.com/2018/09/03/t-sql-tuesday-106-trigger-headaches-or-happiness/"&gt;invited to write about an experience that we&amp;rsquo;ve had with triggers&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/triggers.jpg" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="my-first-encounter-with-triggers-was-overwhelmingly-positive"&gt;My First Encounter with Triggers Was Overwhelmingly Positive&lt;/h2&gt;
&lt;p&gt;When I first edged my way into a Junior DBA-ish role, I worked with a complex application with many large databases. Customers loaded and configured data into a (mostly) OLTP database, and then data was replicated to multiple other systems &amp;ndash; in part to publish data to an adserving platform, in part to transform the data for reporting.&lt;/p&gt;
&lt;p&gt;Triggers were used extensively in these downstream systems to detect changes. It went like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transactional replication publications were set up on the OLTP  (ish) database.&lt;/li&gt;
&lt;li&gt;Transactional replication subscriptions were set up on each downstream server. A dedicated database was used for replication articles on each instance.&lt;/li&gt;
&lt;li&gt;After replication was initialized, DML triggers were created on each article in the subscriber database. For each modification, the trigger would insert a narrow row into a &amp;ldquo;delta&amp;rdquo; table related to that article.&lt;/li&gt;
&lt;li&gt;The &amp;ldquo;delta&amp;rdquo; tables were in their own schema, and contained row identifiers, timestamp columns, and custom indexes for processing. This enabled batches to be efficiently pulled from these tables for processing into the related system.&lt;/li&gt;
&lt;li&gt;Cleanup processes periodically pulled processed rows out of the delta tables in the background (and indexes were designed to prevent the cleanup process from fighting with data processing jobs and inserts)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This design worked very well, and was a very positive introduction to me for triggers&amp;ndash; they worked exactly as they&amp;rsquo;d been designed, and were easy to understand and support. Making schema changes to the tables involved was rarely a problem, and we had established processes for modifying articles and re-initializing replication which worked very well.&lt;/p&gt;
&lt;h2 id="why-didnt-you-use-change-tracking"&gt;Why Didn&amp;rsquo;t You Use Change Tracking?&lt;/h2&gt;
&lt;p&gt;The primary reason that triggers were chosen over Change Tracking was that Change Tracking didn&amp;rsquo;t exist &amp;ndash; these tools were written and tuned well before that feature was released. &lt;/p&gt;
&lt;p&gt;&lt;a href="https://voiceofthedba.com/2018/09/03/t-sql-tuesday-106-trigger-headaches-or-happiness/"&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/image1.jpg"&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Learn more about this TSQL Tuesday&lt;/p&gt;
&lt;p&gt;Looking back, even if we had Change Tracking as an option, we benefited from the granular control we had over this custom system and the elegant simplicity of the implementation. The Change Tracking feature in SQL Server has remained somewhat of an &amp;rsquo;edge feature&amp;rsquo;, and people using it have had to deal with a variety of issues over time - a need to customize the indexes on the change tables, statistics estimate problems with change functions, and problems with cleanup. (I wrote about these &lt;a href="https://www.brentozar.com/archive/2014/06/performance-tuning-sql-server-change-tracking/"&gt;a while back over here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t mean to say that Change Tracking is bad, just that it&amp;rsquo;s not necessarily as &amp;rsquo;easy&amp;rsquo; a solution as you might assume from reading the documentation. You can&amp;rsquo;t simply set it up super fast and skip load testing, or assume that cleanup is going to work like a charm for every scenario &amp;ndash; you need to really think about scaling it&amp;hellip; kinda like you&amp;rsquo;d have to think about scaling it if you were writing your own custom application to handle this type of processing with &amp;hellip; TRIGGERS! There are pros and cons to each approach.&lt;/p&gt;
&lt;p&gt;And even today I wonder&amp;hellip; what if we&amp;rsquo;d been able to get batch mode processing on those delta tables with a little careful custom coding? Hmm&amp;hellip;..&lt;/p&gt;
&lt;h2 id="i-still-kinda-love-triggers"&gt;I Still Kinda Love Triggers&lt;/h2&gt;
&lt;p&gt;A first impression goes along way, you know?&lt;/p&gt;
&lt;p&gt;Sure, people can do terrible things with triggers. But when they&amp;rsquo;re used well, they can be simple, reliable, and incredibly useful.&lt;/p&gt;</description></item><item><title>Watch My Keynote: Adapt and Thrive (25 minutes)</title><link>https://kendralittle.com/2018/09/07/watch-my-keynote-adapt-and-thrive/</link><pubDate>Fri, 07 Sep 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/09/07/watch-my-keynote-adapt-and-thrive/</guid><description>&lt;p&gt;Do you know where your career is going? Do you know what skills you need to be successful in the current climate?&lt;/p&gt;
&lt;h2 id="about-this-keynote"&gt;About This Keynote&lt;/h2&gt;
&lt;p&gt;In this 25 minute keynote, I discuss the challenges and opportunities facing you as a data professional in this ever-changing landscape. You&amp;rsquo;ll also hear recommendations about which skills are needed to help you succeed in your role and how you can in turn support your IT team and business&amp;rsquo; needs.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/xat_Je26qf0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Calendar Reminders for SQL in the City Streamed Free Training Sessions</title><link>https://kendralittle.com/2018/09/03/calendar-reminders-for-sql-in-the-city-streamed-free-training-sessions/</link><pubDate>Mon, 03 Sep 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/09/03/calendar-reminders-for-sql-in-the-city-streamed-free-training-sessions/</guid><description>&lt;p&gt;SQL in the City Streamed is coming up this week! This is an awesome FREE online event, and it&amp;rsquo;s all about learning new things and getting inspired.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQL-IN-THE-CITY-STREAMED-1.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="join-us-live-chat-and-ask-questions"&gt;Join Us Live, Chat, and Ask Questions&lt;/h2&gt;
&lt;p&gt;This event is streamed on YouTube. While the session is going, you can rewind up to three hours or so. But it&amp;rsquo;s the &lt;strong&gt;most&lt;/strong&gt; fun to watch live whenever you can, and ask questions. &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be presenting at the beginning and end of the event. When I&amp;rsquo;m not on screen, I&amp;rsquo;ll be tweeting with the &lt;a href="https://twitter.com/hashtag/sqlinthecity"&gt;#sqlinthecity tag&lt;/a&gt;. I&amp;rsquo;ll also be chatting in Slack about the current presentation, collecting your questions, and giving a little bit of the inside scoop on the event.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d love to have you join me.&lt;/p&gt;
&lt;h2 id="not-set-up-in-slack-yet-no-problem"&gt;Not Set Up in Slack Yet? No Problem&lt;/h2&gt;
&lt;p&gt;You can join the  SQL Community Slack for free anytime. &lt;a href="https://dbatools.io/slack/"&gt;Join here: just request an invite and get set up.&lt;/a&gt; Once you&amp;rsquo;re in, here&amp;rsquo;s a link to the &lt;a href="https://sqlcommunity.slack.com/messages/C67N4A875"&gt;#redgate channel&lt;/a&gt; where we&amp;rsquo;ll be chatting.&lt;/p&gt;
&lt;h2 id="calendar-reminders-for-each-session"&gt;Calendar Reminders for Each Session&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;SQL in the City Streamed&lt;/strong&gt; - September 5, 2018&lt;br&gt;
&lt;a href="https://www.red-gate.com/hub/events/sqlinthecity/index"&gt;Register here for the whole day&lt;/a&gt;. The invites below do &lt;em&gt;not&lt;/em&gt; register you, they simply put reminders on your calendar for the scheduled start times. Do check in on the day to see if we&amp;rsquo;re running on schedule as well - because life happens ;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: this event is now past, so reminders have been removed.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;7AM ET / 12PM GMT - Introduction and Keynote: Adapt and Thrive - Annabel Bradford &amp;amp; Kendra Little&lt;/li&gt;
&lt;li&gt;7:35AM ET / 12:35PM GMT - Yes, You Should Monitor Azure SQL Database - Grant Fritchey&lt;/li&gt;
&lt;li&gt;8:25AM ET / 1:25PM GMT - Wise Up and Get on the Redgate Hub - Chris Kerswell and Chris Unwin&lt;/li&gt;
&lt;li&gt;8:45AM ET / 1:45PM GMT - Azure Machine Learning 101 - Kathi Kellenberger&lt;/li&gt;
&lt;li&gt;9:30AM ET / 2:30PM GMT - Strategies for Solving Compliance Challenges for the Technology Industry- Steve Jones and Chris Unwin&lt;/li&gt;
&lt;li&gt;10AM ET / 3PM GMT - Automating Database Deployments with the Microsoft Stack -  Rob Richardson&lt;/li&gt;
&lt;li&gt;11:05AM ET / 4:05PM GMT - Panel Discussion Q&amp;amp;A: Skillsets for a Successful Career- Steve Jones, Grant Fritchey, Kathi Kellenberger, Rob Richardson&lt;/li&gt;
&lt;li&gt;11:50AM ET / 4:50PM GMT - The Latest from Redgate&amp;rsquo;s Product Teams - Redgate Product Teams&lt;/li&gt;
&lt;li&gt;12:10PM ET / 5:10PM GMT - Keynote Redux: Adapt and Thrive- Kendra Little (a live repeat of the keynote for those joining from later time zones)&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Employee Agreements &amp; Contracts: Best Practices (23 minute video)</title><link>https://kendralittle.com/2018/08/29/employee-agreements-contracts-best-practices-23-minute-video/</link><pubDate>Wed, 29 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/29/employee-agreements-contracts-best-practices-23-minute-video/</guid><description>&lt;p&gt;So you&amp;rsquo;ve got an employee agreement in front of you: now what?&lt;/p&gt;
&lt;p&gt;In this episode, I talk about practical steps you should take to make sure that you understand the terms of your contract, and how to potentially negotiate the terms.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Subscribe&lt;/strong&gt;: &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;Subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id="video"&gt;Video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/b8yTjHvEi2g?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>How to Cause a Simple Spill to tempdb</title><link>https://kendralittle.com/2018/08/22/how-to-cause-a-simple-spill-to-tempdb/</link><pubDate>Wed, 22 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/22/how-to-cause-a-simple-spill-to-tempdb/</guid><description>&lt;p&gt;Sometimes it&amp;rsquo;s useful to know how to cause a problem.&lt;/p&gt;
&lt;p&gt;Maybe you&amp;rsquo;ve never encountered the problem, and want to get hands-on experience. Maybe you&amp;rsquo;re testing a monitoring tool, and want to see if a condition flags an alert. Maybe you&amp;rsquo;re testing out a new client tool, and want to see how it displays it.&lt;/p&gt;
&lt;p&gt;I recently was going through some demos in SQL Operations Studio, and I found that a spill on a sort operator wasn&amp;rsquo;t causing a warning to visibly show in the graphic execution plan.&lt;/p&gt;
&lt;p&gt;I wanted to file an issue on this and let the Ops Studio team know that would be helpful - but my demo code was somewhat complex and required restoring a rather large database. So I set up a quick code sample to cause a spill that could be run in any database.&lt;/p&gt;
&lt;h2 id="whats-the-easiest-way-to-cause-a-spill-on-a-sort-operator"&gt;What&amp;rsquo;s the Easiest Way to Cause a Spill on a Sort Operator?&lt;/h2&gt;
&lt;p&gt;Populate a non-indexed table variable with a bunch of rows, then query the table variable and order the output. Ordering the output will require a sort, and since table variables don&amp;rsquo;t support column statistics, SQL Server won&amp;rsquo;t allocate enough memory for the sort.&lt;/p&gt;
&lt;h2 id="voila-super-quick-sample-code"&gt;Voila, Super Quick Sample Code&amp;hellip;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T1000000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T10000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T100000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ten&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T1000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Credit: This code is a simple adaptation of &lt;a href="https://dba.stackexchange.com/a/131278"&gt;Paul White&amp;rsquo;s answer on this StackExchange question&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="and-heres-what-the-spill-looks-like-in-action"&gt;And Here&amp;rsquo;s What the Spill Looks Like in Action&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a quick view of what the spills look like in SQL Server Management Studio, and then in Operations Studio.&lt;/p&gt;
&lt;p&gt;In Operations Studio, you can currently only see one actual plan at a time (I&amp;rsquo;ve got &lt;a href="https://github.com/Microsoft/sqlopsstudio/issues/1995"&gt;an issue filed for that here&lt;/a&gt;), and there&amp;rsquo;s no little warning on the sort operator, although you can see the details of the spill in the tooltip (I commented on &lt;a href="https://github.com/Microsoft/sqlopsstudio/issues/725"&gt;this issue&lt;/a&gt; to potentially reactivate it).&lt;/p&gt;
&lt;!-- TODO: Image missing: /images/No-warnings-on-sort-operator-with-spill.gif --&gt;
&lt;!-- A quick screencap of the issue turned into an animated gif --&gt;</description></item><item><title>SQL in the City, Fall 2018 - Join Us!</title><link>https://kendralittle.com/2018/08/22/sql-in-the-city-fall-2018-join-us/</link><pubDate>Wed, 22 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/22/sql-in-the-city-fall-2018-join-us/</guid><description>&lt;p&gt;&lt;a href="https://www.red-gate.com/hub/events/redgate-events/sqlinthecity-summit/"&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/redgate-dancing-animals-2.png"&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="online-free"&gt;Online (Free!)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQL in the City Streamed&lt;/strong&gt; – Sept 5, 7AM-12:40PM ET – &lt;em&gt;free&lt;/em&gt; – &lt;a href="https://www.red-gate.com/hub/events/sqlinthecity/index"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="in-person"&gt;In Person&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQL in the City – New York&lt;/strong&gt; – Oct 12 – &lt;em&gt;contact your Redgate rep&lt;/em&gt; &lt;em&gt;–&lt;/em&gt; &lt;a href="https://www.red-gate.com/hub/events/redgate-events/sqlinthecity-summit/new-york"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL in the City – London&lt;/strong&gt; – Oct 18 – GBP £150 until Aug 31, then £200 &lt;em&gt;–&lt;/em&gt; &lt;a href="https://www.red-gate.com/hub/events/redgate-events/sqlinthecity-summit/london"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL in the City – Chicago&lt;/strong&gt; – Oct 26 – &lt;em&gt;contact your Redgate rep&lt;/em&gt; &lt;em&gt;–&lt;/em&gt; &lt;a href="https://www.red-gate.com/hub/events/redgate-events/sqlinthecity-summit/chicago"&gt;Register&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-will-you-learn"&gt;What Will You Learn?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a pretty sweet schedule for each event, featuring folks like &lt;a href="https://twitter.com/gfritchey"&gt;Grant Fritchey&lt;/a&gt;, &lt;a href="https://twitter.com/way0utwest?lang=en"&gt;Steve Jones&lt;/a&gt;, &lt;a href="https://twitter.com/auntkathi?lang=en"&gt;Kathi Kellenberger&lt;/a&gt;, and &lt;a href="https://twitter.com/bobwardms?lang=en"&gt;Bob Ward&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be giving a keynote at the streamed edition of SQL in the City called, &amp;lsquo;Adapt and Thrive&amp;rsquo;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do you know where your career is going? Do you know what skills you need to be successful in the current climate? This keynote will discuss the challenges, as well as the opportunities facing you as a data professional in this ever-changing landscape. You’ll also hear recommendations about which skills are needed to help you succeed in your role and how you can in turn support your IT team and business’ needs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&amp;rsquo;s tons of technical content on the streamed event as well, including sessions on Azure SQL Database, Machine Learning, Deployment Automation, and more.&lt;/p&gt;
&lt;p&gt;The live events have even more content - check out the &lt;a href="https://www.red-gate.com/hub/events/redgate-events/sqlinthecity-summit/london"&gt;sample schedule for London here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="tweet-along-with-the-live-stream"&gt;Tweet Along with the Live Stream&lt;/h2&gt;
&lt;p&gt;I plan to tweet along from the live event: join in the conversation on twitter as you watch with &lt;a href="https://twitter.com/hashtag/SQLinTheCity?src=hash"&gt;#sqlinthecity&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Take the SQLChallenge: Tuning a Stored Procedure</title><link>https://kendralittle.com/2018/08/16/take-the-sqlchallenge-tuning-a-stored-procedure-1-hour-10-minutes/</link><pubDate>Thu, 16 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/16/take-the-sqlchallenge-tuning-a-stored-procedure-1-hour-10-minutes/</guid><description>&lt;p&gt;I&amp;rsquo;ve just published a new &lt;a href="course/tuning-a-stored-procedure-sqlchallenge-1-hour-10-minutes/"&gt;SQLChallenge course&lt;/a&gt;, and I think it&amp;rsquo;s one of the best ones yet.&lt;/p&gt;
&lt;p&gt;Your mission is to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identify which statement is slowing down our stored procedure the most&lt;/li&gt;
&lt;li&gt;Tune the code to speed it up. You can change the query that is slow as well as anything else in the procedure that will help you make that statement faster.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the solution videos, I’ll step through multiple strategies to figure out which statement in the procedure is slowing it down the most – because in real life, you need to have a whole bag of tricks in different situations. &lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQLChallenge-Tuning-a-Stored-Procedure.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Solution scripts and videos include demos of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trace flag 7412, how it impacts sp_WhoIsActive, and live query plans&lt;/li&gt;
&lt;li&gt;Finding the slow query in Query Store - with TSQL as well as the graphic reports&lt;/li&gt;
&lt;li&gt;Finding the slow query in the plan cache&lt;/li&gt;
&lt;li&gt;Methods of rewriting the procedure to tune the query&lt;/li&gt;
&lt;li&gt;Additional code patterns that make tuning procedures simpler.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The challenge script in the first lesson creates a database on your test instance: no need to restore anything, so it&amp;rsquo;s fast to get going.&lt;/p&gt;
&lt;p&gt;&lt;a href="course/tuning-a-stored-procedure-sqlchallenge-1-hour-10-minutes/"&gt;Get started here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="watch-all-the-videos-or-just-what-you-need"&gt;Watch All the Videos, or Just What You Need&lt;/h2&gt;
&lt;p&gt;The course has an hour and ten minutes of videos, each one of which is 15 minutes or less.&lt;/p&gt;</description></item><item><title>Joining Redgate Software</title><link>https://kendralittle.com/2018/08/15/im-joining-redgate-software/</link><pubDate>Wed, 15 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/15/im-joining-redgate-software/</guid><description>&lt;p&gt;I&amp;rsquo;m excited to announce that I&amp;rsquo;m joining the evangelist team at &lt;a href="https://www.red-gate.com/our-company/"&gt;Redgate&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Starting next Monday, I&amp;rsquo;ll be working with &lt;a href="https://twitter.com/way0utwest"&gt;Steve Jones&lt;/a&gt;, &lt;a href="https://twitter.com/gfritchey"&gt;Grant Fritchey&lt;/a&gt;, and &lt;a href="https://twitter.com/auntkathi"&gt;Kathi Kellenberger&lt;/a&gt; &amp;ndash; plus the whole Redgate team.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Im-joining-redgate-blue-sky.png" width="300"&gt;
&lt;/figure&gt;
&lt;h2 id="why-take-on-a-real-job"&gt;Why Take on a &amp;ldquo;Real Job&amp;rdquo;?&lt;/h2&gt;
&lt;p&gt;The last time I had a manager and a normal paycheck was back in the spring of 2011. Since then, I&amp;rsquo;ve had company co-founders, or I&amp;rsquo;ve been doing my own thing, solo.&lt;/p&gt;
&lt;p&gt;When you go out on your own, it can be uncomfortable being your own boss at first: you have no-one to blame but yourself when things go wrong, or if you end up working weekends. But after a while, you get pretty comfortable with it, like anything else. If you keep at it, you&amp;rsquo;ll likely end up thinking, &amp;ldquo;I couldn&amp;rsquo;t ever go back.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But after 7 years, I started asking myself: is this really the best way for me to work? Or is it just what I&amp;rsquo;m used to right now? After all, I&amp;rsquo;ve had great managers in the past, and I know that a great manager can be challenging, supportive, and very valuable.&lt;/p&gt;
&lt;p&gt;I also had a feeling: I missed being part of a team that makes software that changes how people work. Back when I first started out working with data, I worked for a software company with about 150 employees, and I got to be part of the transition from waterfall development to releasing code multiple times per day. Eventually, I worked for Microsoft. I &lt;em&gt;loved&lt;/em&gt; the feeling of being part of a team that shipped software. And increasingly, I&amp;rsquo;ve missed that.&lt;/p&gt;
&lt;p&gt;When I found out that Redgate was hiring an evangelist, I asked myself: is this something you&amp;rsquo;d love to do for ten years or more? The more I learned about the job, the team, and the company, the more I realized that the answer was 100% &amp;ldquo;YES!&amp;rdquo;&lt;/p&gt;
&lt;h2 id="why-ten-years"&gt;Why Ten Years?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve learned a lot about myself at this point in my career. I very much enjoy working and learning. I know some folks would spend their whole life on a sailboat, playing video games, or gardening, if they could, but I&amp;rsquo;m not that person.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying that I&amp;rsquo;ll never retire, but at this particular time and place, I am &lt;em&gt;really&lt;/em&gt; looking forward to the next decade or two of work: right now is such an interesting time to work with data! So much is changing with artificial intelligence, cloud technologies, and even international policies: I&amp;rsquo;m incredibly excited to see what we can do with building software and managing data over this time period. I think Redgate will be an amazing place to be part of these changes.&lt;/p&gt;
&lt;h2 id="why-redgate-values-matter"&gt;Why Redgate? Values Matter&lt;/h2&gt;
&lt;p&gt;I remember being young, and not paying much attention to a company&amp;rsquo;s values statement (if they even had one). That has really changed for me.&lt;/p&gt;
&lt;p&gt;When I visited Redgate headquarters in Cambridge to interview for the position, I was curious if people would embody the company&amp;rsquo;s &lt;a href="https://www.red-gate.com/our-company/careers/overview#our-values"&gt;values&lt;/a&gt;. Here&amp;rsquo;s a quick overview if you don&amp;rsquo;t feel like clicking through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We&amp;rsquo;re reasonable&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;re ingeniously simple&lt;/li&gt;
&lt;li&gt;Transparency helps us continually improve&lt;/li&gt;
&lt;li&gt;We do our best work in teams&lt;/li&gt;
&lt;li&gt;When our customers succeed, so do we&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t be an asshole&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I saw those values in play all around the office on my visit. And I also had a &lt;em&gt;lot&lt;/em&gt; of fun working through the interview process &amp;ndash; which is something I don&amp;rsquo;t remember from past interviews in my life, particularly.&lt;/p&gt;
&lt;p&gt;I took this job because I want to live those values, and I think Redgate is a great place to do it.&lt;/p&gt;
&lt;h2 id="why-redgate-technology-matters-too"&gt;Why Redgate? Technology Matters, Too&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been a fan of Redgate&amp;rsquo;s tools since I first fell in love with SQL Prompt, years ago (ctrl+k ctrl+y for format, fave shortcut forever). And the SQL Compare tools saved the day many times from the point I was a young DBA.&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s not the individual software pieces that drew me. Instead, it&amp;rsquo;s Redgate&amp;rsquo;s focus in recent years on improving the &lt;em&gt;entire&lt;/em&gt; devops experience with SQL Server. Not only was that a brilliant move, but they&amp;rsquo;ve been working towards that vision very consistently, developing products to make development and deployment faster and safer. &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m really impressed by that vision and consistency, and I&amp;rsquo;m so excited to join in.&lt;/p&gt;</description></item><item><title>Employee Agreements &amp; Contracts: Anti-Patterns (31 minute video)</title><link>https://kendralittle.com/2018/08/13/employee-agreements-contracts-anti-patterns-dear-sql-dba-31-minutes/</link><pubDate>Mon, 13 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/13/employee-agreements-contracts-anti-patterns-dear-sql-dba-31-minutes/</guid><description>&lt;p&gt;When you take a new job in software engineering or in IT, within the paperwork there often lurks an employee agreement: a contract between you and your employer. In this half-hour live episode, I talk about why these contracts exist, and multiple anti-patterns you should avoid.&lt;/p&gt;
&lt;p&gt;This is the first of a two part series. In the next episode, I&amp;rsquo;ll discuss best practices for understanding and negotiating the contract.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Subscribe&lt;/strong&gt;: &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;Subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id="video-31-minutes"&gt;Video (31 minutes)&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/MV4lhPCY9b8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Table Value Constructors in TSQL</title><link>https://kendralittle.com/2018/08/07/table-value-constructors-in-tsql/</link><pubDate>Tue, 07 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/07/table-value-constructors-in-tsql/</guid><description>&lt;p&gt;Last week&amp;rsquo;s quiz was on Table Value Constructors in TSQL.&lt;/p&gt;
&lt;p&gt;Table value constructors let you create a dataset on the fly. These can occasionally be useful in writing queries, but I think playing with them has another benefit: they provide a simple, lightweight framework to let you develop your ability to think in sets.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Table-Value-Constructors-in-TSQL.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I wrote this quiz building up to question #4, which I think is a very fun and interesting pattern.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at how folks did on the quiz, and see what table valued constructors can do.&lt;/p&gt;
&lt;h2 id="quiz-answers-and-explanations"&gt;Quiz Answers and Explanations&lt;/h2&gt;
&lt;h2 id="question-1-a-single-table-valued-constructor-how-many-rows-will-this-query-return"&gt;Question 1: a Single Table Valued Constructor! How Many Rows Will This Query Return?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Spider Plant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Chlorophytum comosum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;airplane plant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Aloe Vera&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Aloe vulgari&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Burn Plant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Answer&lt;/strong&gt;: 2&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correct&lt;/strong&gt;: 252 (86%) / &lt;strong&gt;Incorrect&lt;/strong&gt;: 40 (14%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The folks who got this incorrect mostly went for 3: if you haven&amp;rsquo;t used these before, it&amp;rsquo;s unclear how those commas work!&lt;/p&gt;
&lt;p&gt;Table value constructors allow you to specify multiple rows, each surrounded by (round parens). Look for those round parens to identify the rows.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/table-value-constructor-question-1.png"&gt;
&lt;/figure&gt;
&lt;h2 id="question-2-ive-cross-applied-my-tvc-with-another-tvc-how-many-rows-will-this-query-return"&gt;Question 2: I&amp;rsquo;ve Cross Applied My TVC with Another TVC. How Many Rows Will This Query Return?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Heart Leaf Philodendron&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Philodendron cordatum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;green&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;leafy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Answer&lt;/strong&gt;: 4&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correct&lt;/strong&gt;: 239 (82%) / &lt;strong&gt;Incorrect&lt;/strong&gt;: 53 (18%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have two table value constructors, and each of them has one column and two rows.&lt;/p&gt;
&lt;p&gt;If you look at the execution plan for this query, it takes the datasets and joins them with an INNER JOIN with no join predicate: in this case it&amp;rsquo;s as if we did a cross join, and got the cartesian product. Each dataset has two rows, so 2 x 2 = 4.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/table-value-constructor-question-2-289x300.png"&gt;
&lt;/figure&gt;
&lt;h2 id="question-3-something-changed-in-that-apply-how-many-rows-will-this-query-return"&gt;Question 3: Something Changed in That APPLY. How Many Rows Will This Query Return?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Succulents&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Cacti&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; are friends&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Answer&lt;/strong&gt;: 2&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correct&lt;/strong&gt;: 220 (75%) / &lt;strong&gt;Incorrect&lt;/strong&gt;: 72 (25%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whoo, the second table value constructor (v2) is doing something interesting this time: it&amp;rsquo;s referring to the dataset produced by the first table value constructor (v1), and concatenating on a literal value to the &amp;rsquo;thing&amp;rsquo; column.&lt;/p&gt;
&lt;p&gt;The results here have two rows: the second TV creates an additional column.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: You could get the exact same results using a SELECT to define v2 instead of a VALUES clause.
&lt;/div&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/table-value-constructor-question-3-275x300.png"&gt;
&lt;/figure&gt;
&lt;h2 id="question-4-hmmmm-the-cross-apply-got-even-more-interesting-how-many-rows-will-this-return"&gt;Question 4: Hmmmm&amp;hellip; the CROSS APPLY Got Even More Interesting. How Many Rows Will This Return?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;faves&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Ferns&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;being spritzed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;shade&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;humidity&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Succulents&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;well drained soil&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;to dry out a bit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;brighter light&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fav1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fav2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fav3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fav1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fav2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fav3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faves&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Answer&lt;/strong&gt;: 6&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correct&lt;/strong&gt;: 202 (69%) / &lt;strong&gt;Incorrect&lt;/strong&gt;: 90 (31%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I find this to be a very interesting pattern: we are using a table value constructor to do an unpivot operation!&lt;/p&gt;
&lt;p&gt;The first table value constructor (v), is a two row table with four columns: plant, fav1, fav2, and fav3.&lt;/p&gt;
&lt;p&gt;The second table value constructor (v2), does something that seems almost impossible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It refers to the fav1, fav2, and fav3 columns from (v)&lt;/li&gt;
&lt;li&gt;It places all THREE of these columns into a single column named (faves)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is allowed, and it does work.&lt;/p&gt;
&lt;p&gt;The number of rows we get back is the number of values in fav1, fav2, and fav3 - there are two rows and three columns, so 2 x 3 = 6 rows.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/table-value-constructor-question-4.png"&gt;
&lt;/figure&gt;</description></item><item><title>Upcoming Live Podcast Recording Sessions: Employee Agreements and Contracts for DBAs and Devs</title><link>https://kendralittle.com/2018/08/03/upcoming-live-podcast-recording-sessions-employee-agreements-and-contracts-for-dbas-and-devs/</link><pubDate>Fri, 03 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/03/upcoming-live-podcast-recording-sessions-employee-agreements-and-contracts-for-dbas-and-devs/</guid><description>&lt;p&gt;I&amp;rsquo;ve just scheduled two new podcast recording sessions! These are live, half hour sessions - you can join in listen, or share comments. Here&amp;rsquo;s what we&amp;rsquo;ll be talking about&amp;hellip;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Dear-SQL-DBA-Employee-Agreements-and-Contracts.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="employee-agreements-and-contracts-for-dbas-and-devs-anti-patterns"&gt;Employee Agreements and Contracts for DBAs and Devs: Anti-Patterns&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Fri, Aug 10, 4PM PDT&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When you take a new job in IT, within the paperwork there often lurks an employee agreement: a contract between you and your employer. In this half-hour live episode we&amp;rsquo;ll talk about why these contracts exist, and multiple anti-patterns you should avoid.&lt;/p&gt;
&lt;p&gt;This is the first of a two part series. In the following episode, we&amp;rsquo;ll talk best practices for understanding and negotiating the contract.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Registration for this event has now closed&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="employee-agreements-and-contracts-for-dbas-and-devs-best-practices-fri-aug-17-4pm-pdt"&gt;Employee Agreements and Contracts for DBAs and Devs: Best Practices &lt;em&gt;Fri, Aug 17, 4PM PDT&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;So you&amp;rsquo;ve got an employee agreement in front of you: now what? In this half-hour live episode, we&amp;rsquo;ll talk about practical steps you should take to make sure that you understand the terms of your contract, and how to potentially negotiate the terms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Registration for this event has now closed&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="a-note-on-the-timing"&gt;A Note on the Timing&lt;/h2&gt;
&lt;p&gt;I know that 4PM on Fridays isn&amp;rsquo;t great for a lot of folks. But for me, I think it may be a great time to settle down with a cup of tea or a glass of wine and reflect on a topic at the end of the week. I&amp;rsquo;m going to test out recording two episodes in this new time slot and see how it goes.&lt;/p&gt;
&lt;p&gt;If you can&amp;rsquo;t attend live, you can always catch the podcast with a podcast app, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;iTunes&lt;/a&gt;, &lt;a href="https://www.youtube.com/playlist?list=PLoM-GGCV9ZrIgOR5DQ-7eF79_E9ABRVg6"&gt;YouTube&lt;/a&gt;, or &lt;a href="https://dearsqldba.libsyn.com/site/"&gt;via the episode archive&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="episode-inspiration"&gt;Episode Inspiration&lt;/h2&gt;
&lt;p&gt;I recently came across a series of tweets by Stephanie Hulburt, and realized: employee agreements are something I have experience with, from both sides of the table!  I&amp;rsquo;m looking forward to sharing what I know to hopefully make this process easier to navigate for others.&lt;/p&gt;</description></item><item><title>Dear SQL DBA: Remembering Robert Davis, DBA Hero</title><link>https://kendralittle.com/2018/08/02/dear-sql-dba-remembering-robert-davis-dba-hero/</link><pubDate>Thu, 02 Aug 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/08/02/dear-sql-dba-remembering-robert-davis-dba-hero/</guid><description>&lt;p&gt;What makes a person a DBA Hero? In this episode, I talk about how Robert Davis made a huge impact on the SQL Server community, and the traits that Robert displayed that I hope to emulate.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Subscribe&lt;/strong&gt;: If you'd rather listen on the go, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id="links-from-the-video"&gt;Links from the video:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gofundme.com/memorial-and-grief-fund-for-chrissy"&gt;https://www.gofundme.com/memorial-and-grief-fund-for-chrissy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/search?q=%23sqlhelp%20from%3Asqlsoldier"&gt;#sqlhelp from @sqlsoldier&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/npLHKEwaPNs?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>SQL Operations Studio: Keyboard Shortcuts, Actual Plans, &amp; More</title><link>https://kendralittle.com/2018/07/31/sql-operations-studio-keyboard-shortcuts-actual-plans-more/</link><pubDate>Tue, 31 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/31/sql-operations-studio-keyboard-shortcuts-actual-plans-more/</guid><description>&lt;p&gt;Last week I posted a quiz on SQL Operations Studio, &lt;a href="https://docs.microsoft.com/en-us/sql/sql-operations-studio/download"&gt;a free, multi-platform tool from Microsoft.&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This tool is under active development and the features are improving by the day &amp;ndash; which makes it a great time to start trying out the tool and see what you like: because &lt;a href="https://github.com/Microsoft/sqlopsstudio/issues"&gt;you can suggest changes&lt;/a&gt;!&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQL-Operations-Studio-highlighter.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Personally, I find that one of the things like I like to learn first with a tool is how to get around more easily using keyboard shortcuts. As soon as I set up keyboard shortcuts and color themes, I feel more at home in a client.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s make ourselves at home!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="heres-the-answers-to-the-quiz-and-an-overview-of-how-folks-did"&gt;Here&amp;rsquo;s the Answers to the Quiz, and an Overview of How Folks Did&lt;/h2&gt;
&lt;h2 id="question-1-how-can-you-change-the-keyboard-shortcuts-in-sql-ops-studio"&gt;Question 1: How Can You Change the Keyboard Shortcuts in SQL Ops Studio?&lt;/h2&gt;
&lt;p&gt;Correct answers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preferences -&amp;gt; Keyboard Shortcuts&lt;/li&gt;
&lt;li&gt;The SSMS Keymap extension&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Correct: 48 (30%) / Incorrect: 113 (70%)&lt;/p&gt;
&lt;p&gt;Most of the folks who got that one incorrect didn&amp;rsquo;t know about the SSMS Keymap Extension. It&amp;rsquo;s definitely worth checking out, because makes things much easier for some shortcuts that are trickier to map, like enabling actual execution plans.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sql-operations-studio-extensions.png"
alt="Opening up extensions in SQL Ops Studio"&gt;
&lt;/figure&gt;
&lt;h2 id="question-2-to-toggle-a-block-comment-the-built-in-shortcut-is"&gt;Question 2: to Toggle a BLOCK Comment, the Built-In Shortcut Is&amp;hellip;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: Shift+Alt+A&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 43 (27%)&lt;/li&gt;
&lt;li&gt;Incorrect: 118 (73%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think a lot of folks who use SSMS regularly and don&amp;rsquo;t use VSCode may not know what I meant by the question, because SSMS doesn&amp;rsquo;t have this functionality (or if it does, I&amp;rsquo;ve never figured out the shortcut!)&lt;/p&gt;
&lt;p&gt;Here is one version of togging a block comment in action around existing text.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/xw6f658ILr7rF6tkYj/source.gif"
alt="Toggling a block comment in SQL Operations Studio"&gt;
&lt;/figure&gt;
&lt;p&gt;It can also be very nice to insert a block comment and then type in the middle of it right after inserting the brackets!&lt;/p&gt;
&lt;p&gt;If it&amp;rsquo;s possible to fall in love with a keyboard shortcut, I am in love with this one.&lt;/p&gt;
&lt;h2 id="question-3-to-add-a-line-comment-the-built-in-shortcut-is"&gt;Question 3: to Add a LINE Comment, the Built-In Shortcut Is&amp;hellip;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;:  Ctrl+K Ctrl+C (windows) / ⌘K ⌘C (mac) &lt;strong&gt;Mnemonic&lt;/strong&gt;: Control Kansas City (nonsensical, but works for me! Thanks &lt;a href="https://twitter.com/onupdatecascade?lang=en"&gt;Merrill&lt;/a&gt;!)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 83 (52%)&lt;/li&gt;
&lt;li&gt;Incorrect: 78 (48%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some things are the same as in Management Studio! At least for Windows folks.&lt;/p&gt;
&lt;p&gt;For folks, like me, who use a mac, the default shortcut for this uses the Command Key. It is re-mappable if you don&amp;rsquo;t feel like retraining yourself when you switch between clients.&lt;/p&gt;
&lt;h2 id="question-4-to-see-a-searchable-list-of-your-keyboard-shortcuts"&gt;Question 4: to See a Searchable List of Your Keyboard Shortcuts&amp;hellip;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: Ctrl+K Ctrl+S (windows) / ⌘K ⌘S (mac) &lt;strong&gt;Mnemonic&lt;/strong&gt;: Control Keyboard Shortcuts&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 48 (30%)&lt;/li&gt;
&lt;li&gt;Incorrect: 113 (70%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Especially when you&amp;rsquo;re first getting started, you&amp;rsquo;ll be asking a lot: is there a shortcut for &lt;em&gt;x&lt;/em&gt;? You may want to map a shortcut where there isn&amp;rsquo;t one, or change a mapping. That makes this a useful screen to toggle quickly.&lt;/p&gt;
&lt;h2 id="question-5-can-you-get-actual-execution-plans-in-sql-ops-studio"&gt;Question 5: Can You Get &amp;lsquo;Actual&amp;rsquo; Execution Plans in SQL Ops Studio?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Answers&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes, via the command palette&lt;/li&gt;
&lt;li&gt;Yes, via a custom keyboard shortcut&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was news to most people!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 18 (11%)&lt;/li&gt;
&lt;li&gt;Incorrect: 143 (89%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s currently more than one way to get an actual execution plan.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;awesome&lt;/em&gt; easy way is to install the SSMS Keymap Extension (pictured above). It maps the &amp;ldquo;Run Current Query with Actual Plans&amp;rdquo; command (which doesn&amp;rsquo;t have an option in the GUI as of today) to the CTRL+m shortcut.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t feel like using the extension, you can open the Command Palette (Ctrl+Shift+P (windows) / ⌘+Shift+P (mac)) and use the option &amp;ldquo;Run Current Query with Actual Plans&amp;rdquo;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Command-palette.png"
alt="Using the command palette to run a query with actual plans"&gt;
&lt;/figure&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Highlight the query you want to run first, and then use the shortcut (if you&amp;rsquo;re using the extension) or the command palette command. It &lt;em&gt;runs&lt;/em&gt; the query.&lt;/li&gt;
&lt;li&gt;Getting estimated and actual plans for multiple queries is still a bit tricky (&lt;a href="https://github.com/Microsoft/sqlopsstudio/issues/1995"&gt;I filed this issue&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-does-sql-operations-studio-have-a-dark-theme"&gt;BONUS: Does SQL Operations Studio Have a Dark Theme?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: Yes, several&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 78 (48%)&lt;/li&gt;
&lt;li&gt;Incorrect: 83 (52%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know some of you folks out there &lt;em&gt;love&lt;/em&gt; dark themes, so rejoice: you can take your pick. You can also customize them! In my last post, I wrote about &lt;a href="https://kendralittle.com/2018/07/25/changing-your-highlight-color-in-sql-operations-studio//"&gt;customizing my highlight color&lt;/a&gt; and included links to lots of shortcut references.&lt;/p&gt;
&lt;h2 id="havent-tried-it-yet-give-it-a-go"&gt;Haven&amp;rsquo;t Tried It Yet? Give It a Go!&lt;/h2&gt;
&lt;p&gt;While I still switch into SSMS for many tasks, I personally am finding that SQL Ops Studio is a super nice place to write code - so I&amp;rsquo;m using it as much as I can. &lt;a href="https://docs.microsoft.com/en-us/sql/sql-operations-studio/download"&gt;Here&amp;rsquo;s that download link again.&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Changing Your Highlight Color in SQL Operations Studio</title><link>https://kendralittle.com/2018/07/25/changing-your-highlight-color-in-sql-operations-studio/</link><pubDate>Wed, 25 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/25/changing-your-highlight-color-in-sql-operations-studio/</guid><description>&lt;p&gt;I&amp;rsquo;ve been enjoying working with &lt;a href="https://docs.microsoft.com/en-us/sql/sql-operations-studio/download"&gt;SQL Operations Studio&lt;/a&gt; lately - a new, free, cross-platform editor from Microsoft.  The tool is under active development and it&amp;rsquo;s a great time to try it out and suggest changes for how you&amp;rsquo;d like to see the product work. (Here&amp;rsquo;s &lt;a href="https://github.com/Microsoft/sqlopsstudio/issues/1995"&gt;a suggestion I made this week&lt;/a&gt;, for example.)&lt;/p&gt;
&lt;h2 id="tldr-use-workbenchcolorcustomizations"&gt;TLDR: Use workbench.colorCustomizations&lt;/h2&gt;
&lt;p&gt;To change the highlight color quickly to bright yellow, open your user settings file, add code like you see in one of the samples below, and save it.&lt;/p&gt;
&lt;p&gt;Note that a bright yellow highlight color will not work well with themes that put some font in white - configuring editor.selectionForeground currently only works with high contrast themes (&lt;a href="https://github.com/Microsoft/vscode/issues/36490"&gt;issue&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Because of that current limitation, I like a bright yellow highlight specifically with the &amp;ldquo;Light SQL Operations Studio&amp;rdquo; theme:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/* Yellow highlight, works well with Light SQL Operations Studio: */
&amp;#34;workbench.colorCustomizations&amp;#34;: {
&amp;#34;editor.selectionBackground&amp;#34;: &amp;#34;#fffb00&amp;#34;,
&amp;#34;editor.inactiveSelectionBackground&amp;#34;: &amp;#34;#fffb007e&amp;#34;,
&amp;#34;editor.selectionHighlightBackground&amp;#34;: &amp;#34;#fffb007e&amp;#34;
},&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The change will take place as soon as you save the settings file.&lt;/p&gt;
&lt;p&gt;For the &amp;ldquo;Dark SQL Operations Studio&amp;rdquo; theme, which I really like, I find that a purple highlight renders very well:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/* Purple highlight, works well with Dark SQL Operations Studio: */
&amp;#34;workbench.colorCustomizations&amp;#34;: {
&amp;#34;editor.selectionBackground&amp;#34;: &amp;#34;#ae00ff86&amp;#34;,
&amp;#34;editor.inactiveSelectionBackground&amp;#34;: &amp;#34;#ae00ff41&amp;#34;,
&amp;#34;editor.selectionHighlightBackground&amp;#34;: &amp;#34;#ae00ff41&amp;#34;
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;Credit: I figured this out from &lt;a href="https://stackoverflow.com/users/1700375/jakub-zawi%c5%9blak"&gt;Jakub Zawiślak&lt;/a&gt;&amp;rsquo;s answer on t&lt;a href="https://stackoverflow.com/questions/35926381/change-highlight-text-color-in-visual-studio-code"&gt;his question regarding VSCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reference for more editor colors: &lt;a href="https://code.visualstudio.com/docs/getstarted/theme-color-reference#_editor-colors"&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="highlighting-code-is-important-to-me"&gt;Highlighting Code Is Important to Me&lt;/h2&gt;
&lt;p&gt;One of my major uses of SQL Ops studio will be demonstrating code in webcasts and videos, so it&amp;rsquo;s important to me to be able to set a high-contrast highlight for lines of code.&lt;/p&gt;
&lt;p&gt;SQL Ops Studio is based on VSCode, which is very flexible, so I suspected there was a way to do this already. Also, there is a lot of documentation out there on VSCode already, so I searched on &amp;ldquo;VSCode change highlight color&amp;rdquo; to help find my way to the solution.&lt;/p&gt;
&lt;p&gt;But I figured that lots of folks starting out with SQL Ops Studio may not know that, and that this post might be a good introduction to how to change things like this - as well as how to find things by searching for &amp;ldquo;vscode&amp;rdquo;!&lt;/p&gt;
&lt;h2 id="changing-the-highlight-and-testing-themes"&gt;Changing the Highlight and Testing Themes&lt;/h2&gt;
&lt;p&gt;Some handy shortcuts shown in this animation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Opening preferences to edit: &lt;strong&gt;ctrl+,&lt;/strong&gt; (windows) / &lt;strong&gt;cmd+,&lt;/strong&gt; (mac)&lt;/li&gt;
&lt;li&gt;Toggle block comment: &lt;strong&gt;shift+option+a&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Saving file: &lt;strong&gt;ctrl+s&lt;/strong&gt; (windows) / &lt;strong&gt;cmd+s&lt;/strong&gt; (mac)&lt;/li&gt;
&lt;li&gt;Viewing/changing color themes: &lt;strong&gt;ctrl+k ctrl+t&lt;/strong&gt; (windows) / &lt;strong&gt;cmd+k cmd+t&lt;/strong&gt; (mac)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Shortcut references: &lt;a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf"&gt;windows&lt;/a&gt;, &lt;a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf"&gt;mac&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what it looks like to change the highlight to bright yellow, and to preview it in different themes:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/yLaIbalfLgHGaJxamW/source.gif"
alt="Animation showing how to change the highlight color to bright yellow and preview it in different themes in SQL Operations Studio"&gt;
&lt;/figure&gt;
&lt;p&gt;Note that you don&amp;rsquo;t truly see how the highlight will be implemented until you fully select a theme (preview mode is slightly dimmed), and that the highlight color persists across different themes (which I think is awesome).&lt;/p&gt;
&lt;p&gt;This screencap was taken from a mac, using Camtasia screencap to capture the keystrokes.&lt;/p&gt;</description></item><item><title>CROSS APPLY in T-SQL: Why to APPLY</title><link>https://kendralittle.com/2018/07/24/cross-apply-in-t-sql-why-to-apply/</link><pubDate>Tue, 24 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/24/cross-apply-in-t-sql-why-to-apply/</guid><description>&lt;p&gt;Michelle asked a great question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In your own words, why would one want to use a cross apply operator rather than a join operator? I’m old school, and I’m just not getting why a cross apply would be so much better to use than a join.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s my top 3 favorite uses for CROSS APPLY and OUTER APPLY:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;APPLY is fantastic for calling table valued functions. I didn’t include questions about those in the quiz, simply for the purposes of keeping the code simple, and because I wanted the quiz to be about thinking through how apply works — but it’s still the #1 use.&lt;/li&gt;
&lt;li&gt;Another thing I might use it for is when a query needs a correlated subquery — somewhat like an inline function.&lt;/li&gt;
&lt;li&gt;And I also like it for queries that have a calculation that needs to be done and which is referenced in multiple columns in the query, or perhaps also in a predicate and the select. You can perform the computation once in the apply and then reference it multiple times. That way if you have to change the formula later on, you only have to change it in once place, plus I find it’s easier to read in some cases.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But it can do even more&amp;hellip;&lt;/p&gt;
&lt;p&gt;It can help you (un) pivot data. Check out Kenneth Fisher&amp;rsquo;s &lt;a href="https://sqlstudies.com/2013/04/01/unpivot-a-table-using-cross-apply/"&gt;example here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Brad Schulz’s post here has code samples for those, plus more things like showing how it can be useful for shredding XML: &lt;a href="http://bradsruminations.blogspot.com/2011/04/t-sql-tuesday-017-it-slices-it-dices-it.html"&gt;http://bradsruminations.blogspot.com/2011/04/t-sql-tuesday-017-it-slices-it-dices-it.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Brad gets a bit jokey at the end of the post, but there’s a lot of valid uses along the way.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="quiz-resultsanswersexplanations-cross-apply"&gt;Quiz Results/Answers/Explanations: CROSS APPLY&lt;/h2&gt;
&lt;p&gt;The questions in this quiz are based on two tables, created and populated with the following commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produces two tables which look like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbo_t1-1.png"&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbo_t2.png"&gt;
&lt;/figure&gt;
&lt;h3 id="question-1-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;Question 1: If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer: The results of COUNT(*) based on an inner join between the two tables&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 106 (42%)&lt;/li&gt;
&lt;li&gt;Incorrect: 146 (58%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know, it&amp;rsquo;s weird, there&amp;rsquo;s a 1/0 in there which seems like it would produce a divide by zero error! But that bit of code never gets evaluated in this case, and the query runs successfully.&lt;/p&gt;
&lt;p&gt;Sometimes a query using APPLY can be &amp;ldquo;transformed&amp;rdquo; into a join operation, and this is one of those cases. You can read more about this &lt;a href="http://www.sqlservercentral.com/articles/APPLY/69954/"&gt;in Paul White&amp;rsquo;s article here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most of the time, if you want a join, you should use a join. However, it&amp;rsquo;s definitely useful to know that APPLY can be used this way for when you are reading and editing code written by others.&lt;/p&gt;
&lt;h3 id="question-2-will-these-queries-return-the-same-result"&gt;Question 2: Will These Queries Return the Same Result?&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer: yes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 140 (56%)&lt;/li&gt;
&lt;li&gt;Incorrect: 112 (44%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case, the second query will be rewritten to use an inner join, just like the first query. One method you can use to verify this is to look at the execution plan for both queries (and you can obviously run them and compare the results).&lt;/p&gt;
&lt;p&gt;Both queries return a count of 2.&lt;/p&gt;
&lt;p&gt;Here are the estimated plans for both queries:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/explain-plan-inner-joins.png"&gt;
&lt;/figure&gt;
&lt;h3 id="question-3-will-these-queries-return-the-same-result"&gt;Question 3: Will These Queries Return the Same Result?&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OUTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer: no&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 198 (79%)&lt;/li&gt;
&lt;li&gt;Incorrect: 54 (21%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first query returns the count of 2. The second query returns a count of 5.&lt;/p&gt;
&lt;p&gt;This is because the first query is implemented as an inner join, and the second query is implemented as an outer join.&lt;/p&gt;
&lt;h3 id="question-4-will-these-queries-return-the-same-result"&gt;Question 4: Will These Queries Return the Same Result?&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t1c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer: yes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 161 (64%)&lt;/li&gt;
&lt;li&gt;Incorrect: 91 (36%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is an example of using a CROSS APPLY to compute a calculation.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s pretty trivial in this case, but I find this can be very useful in the case of complex queries where you refer to the result of a calculation more than once &amp;ndash; doing this can allow you to only do the computation in once place and then refer to it many times. Not only can this make the query more readable sometimes, it can limit the errors if you need to change the calculations (because you&amp;rsquo;re changing it in fewer places.)&lt;/p&gt;</description></item><item><title>Dear SQL DBA: Why I Rarely Mention Service Broker</title><link>https://kendralittle.com/2018/07/19/dear-sql-dba-why-dont-you-teach-service-broker/</link><pubDate>Thu, 19 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/19/dear-sql-dba-why-dont-you-teach-service-broker/</guid><description>&lt;p&gt;I&amp;rsquo;ve gotten a few questions about whether I recommend learning Service Broker, and recently I was asked if I&amp;rsquo;m planning to make any courses on Service Broker.&lt;/p&gt;
&lt;h2 id="about-this-episode"&gt;About This Episode&lt;/h2&gt;
&lt;p&gt;In this 23 minute episode, I talk about why I personally haven&amp;rsquo;t become an expert with Broker, the factors that I believe play into Service Broker adoption, and other resources online for learning Service Broker in SQL Server.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Subscribe&lt;/strong&gt;: If you'd rather listen on the go, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss&lt;/a&gt;
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WDAq7k4Sdeg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>The BREAK Keyword in Transact SQL</title><link>https://kendralittle.com/2018/07/16/break-in-transact-sql/</link><pubDate>Mon, 16 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/16/break-in-transact-sql/</guid><description>&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/language-elements/break-transact-sql"&gt;BREAK&lt;/a&gt; is a useful piece of control-of-flow language in SQL Server, but it only works in specific situations.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Break-keyword-300x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="break-questions-answers-and-explanations"&gt;Break Questions, Answers, and Explanations&lt;/h2&gt;
&lt;h2 id="1-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;1) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;BREAK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 135, Level 15, State 1, Line 6
Cannot use a BREAK statement outside the scope of a WHILE statement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How&amp;rsquo;d people do?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 237 (77%)&lt;/li&gt;
&lt;li&gt;Incorrect: 70 (23%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know, it seems like this should work! But, in fact, BREAK only breaks you out of a WHILE loop.&lt;/p&gt;
&lt;p&gt;For other purposes, you may want to use &lt;a href="https://kendralittle.com/2018/06/29/order-by-offset-and-fetch-in-tsql/"&gt;RETURN&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="2-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;2) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BREAK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer: 2&lt;/p&gt;
&lt;p&gt;This one was a little trickier&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 202 (66%)&lt;/li&gt;
&lt;li&gt;Incorrect: 105 (34%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case BREAK will cause us to exit that WHILE loop (so we won&amp;rsquo;t be stuck in it forever). BREAK doesn&amp;rsquo;t cause the execution of the whole batch to terminate, though, so we go on to the next statement, and PRINT 2 is executed.&lt;/p&gt;
&lt;h2 id="3-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;3) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BREAK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 135, Level 15, State 1, Line 6
Cannot use a BREAK statement outside the scope of a WHILE statement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This one foiled even more folks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 135 (44%)&lt;/li&gt;
&lt;li&gt;Incorrect: 172 (56%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key to this one is that we haven&amp;rsquo;t defined a statement block. That means that the WHILE statement applies to the next statement only. The IF statement also applies to the next statement only. The BREAK is left out in the cold, and it will throw an error if it is not part of a WHILE loop.&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s a tricky question, because it might seem like SQL Server would get to the PRINT and be stuck in an infinite loop, never getting to the point that it throws the error. That doesn&amp;rsquo;t happen - as soon as we execute, the parse process sees the mistake and we get the error right away.&lt;/p&gt;
&lt;h2 id="4-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;4) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BREAK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer: Commands completed successfully.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 239 (78%)&lt;/li&gt;
&lt;li&gt;Incorrect: 68 (22%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case, the BREAK and the PRINT are within a defined BEGIN / END statement block together, inside a WHILE loop. When we hit the BREAK it exits the loop, never getting to the PRINT statement.&lt;/p&gt;</description></item><item><title>What the Microsoft MVP Award Means to Me in 2018</title><link>https://kendralittle.com/2018/07/11/what-the-microsoft-mvp-program-means-to-me-in-2018/</link><pubDate>Wed, 11 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/11/what-the-microsoft-mvp-program-means-to-me-in-2018/</guid><description>&lt;p&gt;I recently received my seventh &amp;ldquo;Most Valuable Professional&amp;rdquo; award from Microsoft. Oddly, I don&amp;rsquo;t think I&amp;rsquo;ve ever written about what this award means to me until this point.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Microsoft-MVP-Award-2017-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;In part, this is because when &amp;ldquo;renewals&amp;rdquo; come out, there are always folks I know who have &lt;em&gt;not&lt;/em&gt; been renewed &amp;ndash; and for many people that can be a painful time. It&amp;rsquo;s never easy to celebrate when others are hurting.&lt;/p&gt;
&lt;p&gt;I wanted to write this post not to brag, but to discuss why this award has come to mean more to me&amp;ndash; and why I&amp;rsquo;m eager for &lt;em&gt;you&lt;/em&gt;, friend reader, to compete with me for your own MVP Award.&lt;/p&gt;
&lt;h2 id="at-first-i-just-wanted-to-be-in-the-club"&gt;At First, I Just Wanted to Be in the Club&lt;/h2&gt;
&lt;p&gt;When I first began giving talks on SQL Server, I learned about the &lt;a href="https://mvp.microsoft.com/en-us/Overview"&gt;Microsoft MVP program&lt;/a&gt; from other speakers. I had no idea what it was before then, even as a Microsoft employee I had not heard of it because my role was not directly within a product group.&lt;/p&gt;
&lt;p&gt;I learned that there is a private email distribution list for SQL Server MVPs (now known as Data Platform MVPs), which connects MVPs with each other and Microsoft developers and program managers. I learned that there is a regular conference for MVPs, the MVP Summit, which provides training, networking, and often previews of upcoming features in the products.&lt;/p&gt;
&lt;p&gt;And I learned that being an MVP was recognized by speakers in the community as being somewhat special.&lt;/p&gt;
&lt;p&gt;Of course, I wanted to be special, too!&lt;/p&gt;
&lt;p&gt;It took some time before I ever came close to being nominated for the MVP program, but I first received the MVP Award in 2012.&lt;/p&gt;
&lt;h2 id="it-took-me-a-while-to-appreciate-the-benefits-of-the-award"&gt;It Took Me a While to Appreciate the Benefits of the Award&lt;/h2&gt;
&lt;p&gt;You know that old Groucho Marx quote about not wanting to be a member of any club that will have you? Once I first received the award, I was glad that I was &amp;ldquo;special,&amp;rdquo; but I quickly lost sight of its value.&lt;/p&gt;
&lt;p&gt;This has more to do with me than it does with the award: when you receive a lot of email and are busily starting a company, joining a large distribution list may not be as glorious as you thought.&lt;/p&gt;
&lt;p&gt;And when you have a lot of social anxiety at conferences, you may end up being less excited about an additional conference each year. What seemed like a great networking opportunity in theory transforms into a reality when you wish you had the nerve to be out meeting others, but find yourself clinging to people you know well and making plans to safely return home to everyday work and established patterns.&lt;/p&gt;
&lt;h2 id="over-the-years-i-grew-up-a-bit"&gt;Over the Years, I Grew Up a Bit&lt;/h2&gt;
&lt;p&gt;I continued my community involvement over time. I blogged about SQL Server and I ventured into videos. I spoke at conferences, I wrote free troubleshooting scripts, I gave free webcasts, I created training courses and gave many away for free. I put together SQL Server themed posters and desktop wallpapers. I had fun.&lt;/p&gt;
&lt;p&gt;To be honest, I did these things because they were good for me &lt;em&gt;and&lt;/em&gt; for the community. Blogging helped me learn things, remember things, and it also helped build a consulting and training business. Presenting, video making, and everything is similar: in the modern world, the more information you share openly, the more benefits can come back to you. Contributing to the community while realizing the benefits for yourself is perfectly OK with Microsoft, too: the point is that you&amp;rsquo;re contributing.&lt;/p&gt;
&lt;p&gt;Earning the MVP Award repeatedly has been a side effect of my efforts. I have generally only focused on earning the MVP Award when I have come upon the annual task of quantifying the &amp;ldquo;reach&amp;rdquo; of my contributions in page views, video performance, and students reached.&lt;/p&gt;
&lt;p&gt;Along the way, I have matured as a person. I started &lt;a href="https://kendralittle.com/2017/11/08/dear-sql-dba-i-thought-i-was-an-introvert-turns-out-i-was-anxious-as/"&gt;working on my anxiety&lt;/a&gt;, and learned techniques to &lt;a href="https://kendralittle.com/2018/02/26/infographic-conference-prep-for-anxious-folk/"&gt;get the most out of conferences&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I attended the MVP Summit this past year and enjoyed it immensely, far more than ever before. I made more connections with other MVPs than I had thought possible, I learned a lot during sessions, and I &lt;em&gt;had fun&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="im-excited-to-be-a-microsoft-mvp---for-as-long-as-theyll-have-me"&gt;I&amp;rsquo;m Excited to Be a Microsoft MVP - for as Long as They&amp;rsquo;ll Have Me&lt;/h2&gt;
&lt;p&gt;Part of maturing as a person is realizing how lucky I am to receive recognition from Microsoft, when I am doing things that are also good for myself. I write and present according to my own interests, I don&amp;rsquo;t follow any specific guidelines or tailor my content with the award in mind.&lt;/p&gt;
&lt;p&gt;I work on what I think is important and useful for myself, for developers, and for DBAs, and I often focus on &amp;ldquo;evergreen&amp;rdquo; content rather than the latest offering &amp;ndash; unless I think the latest offering may be very interesting or awesome for my audience.&lt;/p&gt;
&lt;p&gt;And so, I am very grateful that Microsoft recognizes my work as important. I&amp;rsquo;m thrilled that they seem to be inviting me to visit campus for the MVP Summit again! That they will help me understand features that are coming, and that they are open to my feedback on how to shape the features. (Note: this openness to feedback is not exclusive to the MVP program, by the way. One way that MVPs can be useful is by connecting customers with interesting use cases and needs to the right Microsoft employees.)&lt;/p&gt;
&lt;p&gt;I believe that I&amp;rsquo;m getting better at being an MVP, simply by getting better at taking advantage of the benefits the award provides. I don&amp;rsquo;t plan to change much in terms of contributions: I&amp;rsquo;m still going to follow my interests and work in the areas where I have a passion. But while I do have the award, I&amp;rsquo;m going to make the most of it.&lt;/p&gt;
&lt;p&gt;Thanks to Microsoft, and thanks also to my fellow MVPs, past and present, for making the program awesome and engaging.&lt;/p&gt;
&lt;h2 id="if-you-would-like-to-be-a-microsoft-mvp"&gt;If You Would Like to Be a Microsoft MVP&amp;hellip;&lt;/h2&gt;
&lt;p&gt;I encourage you to contribute to the community. Absolutely do it in a way that &lt;em&gt;also&lt;/em&gt; benefits you: writing blog posts on a domain branded under your own name can be a great resume builder! Publishing fun YouTube videos and building a strong channel following can help the community, and help build your reputation at the same time.&lt;/p&gt;
&lt;p&gt;Building a profile answering questions on an online Q&amp;amp;A site and answering questions on Twitter can help, too &amp;ndash; but do think about doing these things in a way where you can summarize the number of people you&amp;rsquo;ve helped, and show off your work to your current employer, to your future employers, and also on something like an MVP application. (Example: for each question you answer, why not capture the information in a blog post as well, with supporting references, that links to the question? That helps you keep track, and also build an index of your work.)&lt;/p&gt;
&lt;p&gt;Although I began this blog post with a note that sometimes folks don&amp;rsquo;t get their MVP Award renewed, also know this: there always needs to be room in the program for &lt;em&gt;new&lt;/em&gt; MVPs. I love seeing the list of new folks in the program. While I plan to contribute as much as I can for as long as I can, I believe part of me will smile when someday I don&amp;rsquo;t receive the award and instead see a lovely new crop of folks who are excited to join the &amp;ldquo;special club.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="cmon-folks-make-it-even-harder-for-me-to-make-the-cut-for-re-award-next-year"&gt;C&amp;rsquo;mon Folks! Make It Even Harder for Me to Make the Cut for Re-Award Next Year!&lt;/h2&gt;
&lt;p&gt;The bar is already high to be an MVP, but I encourage you to join in and contribute: bring your own voice and fresh new take on community involvement. Start wherever you want to start, and build from there: be persistent, and you&amp;rsquo;ll find your style, your opinions, your special angle on this whole thing.&lt;/p&gt;
&lt;p&gt;I think your stories and articles and code can be compelling. I think they can help a lot of people.&lt;/p&gt;
&lt;p&gt;I think you can be so awesome that it may be tempting for Microsoft to cut folks like me from the list, and add you in, so they can hear your voice more clearly. And I want you to be that awesome!&lt;/p&gt;
&lt;p&gt;Because the more complex and interesting and welcoming we are as a community, &lt;a href="https://twitter.com/Kendra_Little/status/1014593447653707776"&gt;the stronger we will be&lt;/a&gt;. By contributing, you help me, too.&lt;/p&gt;</description></item><item><title>Using RETURN in Transact SQL: Quiz Results</title><link>https://kendralittle.com/2018/07/09/using-return-in-transact-sql-quiz-results/</link><pubDate>Mon, 09 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/09/using-return-in-transact-sql-quiz-results/</guid><description>&lt;p&gt;RETURN is a &amp;ldquo;control of flow&amp;rdquo; language keyword in Transact-SQL. It&amp;rsquo;s very useful for managing when code does &amp;ndash; and does NOT &amp;ndash; get executed in procedural code, and it can also be used to communicate the status from procedural code.&lt;/p&gt;
&lt;p&gt;But not everyone knows how to use RETURN, and learning about it can be awkward because of some quirks of SQL Server Management Studio. It is well worth taking the time to get used to it, though!&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Quiz_-RETURN-1.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="quiz-results-and-discussion-of-return"&gt;Quiz Results and Discussion of RETURN&lt;/h2&gt;
&lt;p&gt;I changed the wording on question #4 on July 4 after Nick posted a message about the wording, and he was totally right: there was more than one defensible correct answer.&lt;/p&gt;
&lt;p&gt;Changing the wording did not significantly change the average score, it turns out. The average percentage dropped from 65% to 64% once that question was clarified. (That&amp;rsquo;s not a bad percentage at all: I think a lot of folks aren&amp;rsquo;t used to using RETURN, and hopefully the quiz made them curious on how it can be useful.)&lt;/p&gt;
&lt;h2 id="1-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;1) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Correct: 292 (78%)&lt;/li&gt;
&lt;li&gt;Incorrect: 84 (22%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Answer: 2&lt;/p&gt;
&lt;p&gt;The key to this question is that RETURN controls flow within a given batch, and the default batch separator is the word &amp;ldquo;GO&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;If you want to stop the execution of a script you&amp;rsquo;re running in SSMS, the RETURN keyword won&amp;rsquo;t stop everything if you have more than one batch.&lt;/p&gt;
&lt;h2 id="2-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;2) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Correct: 249 (66%)&lt;/li&gt;
&lt;li&gt;Incorrect: 127 (34%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Answer: Commands completed successfully.&lt;/p&gt;
&lt;p&gt;In this question, RETURN is shown inside a single batch. It will stop the flow of execution before the PRINT statement, and SSMS will simply report, &amp;ldquo;Commands completed successfully.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="3-if-you-run-this-code-in-a-sql-server-management-studio-session-what-will-appear-in-the-messages-window"&gt;3) If You Run This Code in a SQL Server Management Studio Session, What Will Appear in the Messages Window?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Correct: 256 (68%)&lt;/li&gt;
&lt;li&gt;Incorrect: 120 (32%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Answer: Commands completed successfully.&lt;/p&gt;
&lt;p&gt;This time we have everything in one batch statement again, but we have the RETURN inside of a BEGIN / END block.&lt;/p&gt;
&lt;p&gt;The gist of this question is: does RETURN cause it to exit only the BEGIN/END block, or that entire block of code?&lt;/p&gt;
&lt;p&gt;The answer is that it causes it to exit from the entire block of code, it will never reach the PRINT statement.&lt;/p&gt;
&lt;h2 id="4-given-this-code-what-appears-in-the-messages-window-of-ssms-after-you-execute-dbotest"&gt;4) Given This Code, What Appears in the Messages Window of SSMS After You Execute dbo.test?&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Correct: 29 (58%)&lt;/li&gt;
&lt;li&gt;Incorrect: 21 (42%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Answer: Commands completed successfully.&lt;/p&gt;
&lt;p&gt;The wording in this post is the &amp;ldquo;corrected&amp;rdquo; wording. The original wording was less clear, so I&amp;rsquo;ve reported the correct/incorrect ratios for July 5 - 9, after the wording was changed.&lt;/p&gt;
&lt;p&gt;This one may seem silly, but I think it&amp;rsquo;s very important to know that SSMS will &lt;em&gt;not&lt;/em&gt; report anything in the Messages tab in the case. It doesn&amp;rsquo;t mean that RETURN didn&amp;rsquo;t work, it simply means that the SSMS interface doesn&amp;rsquo;t show it!&lt;/p&gt;
&lt;p&gt;If you want to capture the value that RETURN sends back and do something with it, you need to assign it to something, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tinyint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Used in this way, RETURN can be incredibly useful when it comes to returning status from procedural code.&lt;/p&gt;</description></item><item><title>The Right to Be Erased is Coming to California, Along with Other Privacy Rights</title><link>https://kendralittle.com/2018/07/05/the-right-to-be-erased-is-coming-to-california-along-with-other-privacy-rights/</link><pubDate>Thu, 05 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/05/the-right-to-be-erased-is-coming-to-california-along-with-other-privacy-rights/</guid><description>&lt;p&gt;In the last year, developers and DBAs have heard a lot about the &lt;a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation"&gt;General Data Protection Regulation (GDPR) law&lt;/a&gt; passed by the European Union. These regulations not only impact companies that are incorporated in Europe, but all companies processing the data of Europeans.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Right-to-be-erased-300x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;These new ground rules include obtaining consent before adding people to mailing lists, allowing people to revoke that consent easily, and requiring processes for handling personal data to protect the data by default.&lt;/p&gt;
&lt;p&gt;The GDPR also allows individuals in the EU to request copies of information that a company holds about them, and grants &amp;ldquo;the right to erasure,&amp;rdquo; or the right to have their data removed. This is particularly an interesting issue when it comes to data stored in backups, and copies of data, which are frequently used for software development, test, and analysis.&lt;/p&gt;
&lt;h2 id="these-rights-are-now-coming-to-the-united-states"&gt;These Rights Are Now Coming to the United States&lt;/h2&gt;
&lt;p&gt;If you didn&amp;rsquo;t pay much attention to the GDPR because your customers are located in the United States, it&amp;rsquo;s a great time to start reading!&lt;/p&gt;
&lt;p&gt;Check out this post from the &lt;a href="https://epic.org/2018/06/california-passes-milestone-pr.html"&gt;Electronic Privacy and Information Center (EPIC)&lt;/a&gt; regarding the &lt;a href="https://leginfo.legislature.ca.gov/faces/billTextClient.xhtml?bill_id=201720180AB375"&gt;California Consumer Privacy Act of 2018, also known as AB-375&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Act will establish the right of residents of California to know what personal information about them is being collected; to know whether their information is sold or disclosed and to whom; to limit the sale of personal information to others; to access their information held by others; and to obtain equal service and price, even if they exercise their privacy rights. The Act will allow individuals to delete their data and it will establish opt-in consent for those under 16.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="data-breach-damages-could-add-up-fast"&gt;Data Breach Damages Could Add Up Fast&lt;/h2&gt;
&lt;p&gt;The Privacy act also allows consumers who are the victims of data breaches to seek damages. A lost laptop with a development database containing, say, 1 million unprotected email addresses might be liable for up to $750 of damages for each person impacted, or actual damages (whichever is higher).&lt;/p&gt;
&lt;p&gt;The case for encrypting personal data in production, and masking or removing it from non-production environments has never looked so strong.&lt;/p&gt;
&lt;h2 id="concerned-about-privacy-this-is-progress"&gt;Concerned About Privacy? This Is Progress&lt;/h2&gt;
&lt;p&gt;You may associate the GDPR with generating more email, rather than reducing it. Most of us got a flood of email around GDPR enforcement day.&lt;/p&gt;
&lt;p&gt;But in the long run, these are tools that give you, as an individual, a voice to say whether or not you want to receive messages, and to exercise control over what data companies maintain about you. The fact that California has now passed this privacy act gives companies in the United States (and those who handle data for people in the United States) even more reason to apply privacy protection by default to all of their customers, because more states may be next.&lt;/p&gt;
&lt;h2 id="are-you-a-dba-or-developer-this-can-look-great-on-your-resume"&gt;Are You a DBA or Developer? This Can Look Great on Your Resume&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve met more than one person who has had a tough time scrambling to get their processes and scripts ready for the GDPR regulation. And it wasn&amp;rsquo;t always fun.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve already started down that road, the California Consumer Privacy Act is just another reason that what you&amp;rsquo;ve done is worthwhile, and that the business processes and code patterns you&amp;rsquo;ve developed are going to look just great on your resume and work well for you in the future.&lt;/p&gt;
&lt;p&gt;If you haven&amp;rsquo;t started down this road yet, now is the time to start investigating the types of data your company processes, the nature of the data, and how you protect that data. When thinking about &amp;ldquo;data,&amp;rdquo; this isn&amp;rsquo;t your production databases, it&amp;rsquo;s &lt;em&gt;all&lt;/em&gt; the copies of that data. Even if your company is small enough that you won&amp;rsquo;t fall under the California Data Protection act, developing privacy processes and practices is now part of the job descriptions of DBAs and developers.&lt;/p&gt;
&lt;p&gt;While GDPR is already in effect, the California Consumer Privacy Act is scheduled to go into effect on January 1, 2020.&lt;/p&gt;</description></item><item><title>Find the Scalar Function Call: What It Means When It Hides in Probe Residual</title><link>https://kendralittle.com/2018/07/02/find-the-scalar-function-call-what-it-means-if-its-hiding-in-probe-residual/</link><pubDate>Mon, 02 Jul 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/07/02/find-the-scalar-function-call-what-it-means-if-its-hiding-in-probe-residual/</guid><description>&lt;p&gt;User defined functions are fairly simple to create in SQL Server, but figuring out exactly how they are being used can take a little time - even in a simple execution plan. This is because the functions can be tucked away into lots of different operators in the plan, even join operators.&lt;/p&gt;
&lt;p&gt;The good news: once you learn what to look for, it&amp;rsquo;s not terribly complicated. There are some fancy terms involved, but the definitions are pretty simple.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a quick look at a function call hidden in a hash match operator, which is being used to implement an inner join.&lt;/p&gt;
&lt;h2 id="the-estimated-query-execution-plan"&gt;The Estimated Query Execution Plan&lt;/h2&gt;
&lt;p&gt;This query uses the Microsoft &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters&lt;/a&gt; sample database. The query calls the built in scalar user defined function, Website.CalculateCustomerPrice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceLineID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Invoices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceLines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Website&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;CalculateCustomerPrice&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StockItemID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceDate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnitPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the query execution plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-with-function-call.png"&gt;
&lt;/figure&gt;
&lt;p&gt;There&amp;rsquo;s not a lot of places for the function call to hide in this particular plan, right? No Compute Scalars to look into at all.&lt;/p&gt;
&lt;p&gt;If we look at the properties of the Hash Match join, we can find the function call:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/probe-residual-with-funciton-call.png"&gt;
&lt;/figure&gt;
&lt;h2 id="how-does-the-hash-join-work"&gt;How Does the Hash Join Work?&lt;/h2&gt;
&lt;p&gt;The description at the top of this tool tip is quite helpful when it comes to remembering how hash matches work: SQL Server is building a table in memory from the Sales.Invoices table. It&amp;rsquo;s then &amp;ldquo;probing&amp;rdquo; into it with items from the Sales.InvoicesLines table.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;Hash Keys Probe&amp;rdquo; part of the tool tip tells us that it is looking for matches based on the InvoiceID column (our join column).&lt;/p&gt;
&lt;h2 id="what-about-the-probe-residual"&gt;What About the &amp;lsquo;Probe Residual&amp;rsquo;?&lt;/h2&gt;
&lt;p&gt;After we find matches based on the customer id, we have more work &amp;ldquo;left over&amp;rdquo;: that&amp;rsquo;s the &amp;ldquo;residual&amp;rdquo; bit.&lt;/p&gt;
&lt;p&gt;For every row that matches, SQL Server is plugging values into the Website.CalculateCustomerPrice() function and comparing the result to the Unit price column, just like we asked for in the where clause.&lt;/p&gt;
&lt;p&gt;In other words, this is happening for every row in Sales.InvoiceLines that has a matching row in Sales.Invoices.&lt;/p&gt;
&lt;p&gt;Which is every single invoice &amp;amp; invoice line, as it turns out.&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re ever looking for an example of a query where collecting an actual execution plan dramatically slows down execution (observe effect), this is a good one. On instances I&amp;rsquo;ve tested, this query takes 14-18 seconds to run when no plan is collected, and about a minute longer when you enable actual plan collection.&lt;/p&gt;
&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re looking at execution plans, it can be very tricky to spot user defined functions in the plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need to not only check into Compute Scalar operators if they are around, but also look carefully at the properties of other operators, including joins&lt;/li&gt;
&lt;li&gt;If you spot the function call as part of a &amp;ldquo;probe residual&amp;rdquo; on a hash join, it is being applied to every row that meets the initial join criteria&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ORDER BY, OFFSET, and Fetch in TSQL</title><link>https://kendralittle.com/2018/06/29/order-by-offset-and-fetch-in-tsql/</link><pubDate>Fri, 29 Jun 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/06/29/order-by-offset-and-fetch-in-tsql/</guid><description>&lt;p&gt;My most recent Quizletter featured a quiz on ORDER BY in TSQL, complete with questions on the OFFSET and FETCH clauses which we got in SQL Server 2012.&lt;/p&gt;
&lt;p&gt;One great thing about teaching TSQL School is that it reminds me of these cool options that can be easy to forget.&lt;/p&gt;
&lt;h2 id="overall-quiz-stats"&gt;Overall Quiz Stats&lt;/h2&gt;
&lt;p&gt;Folks did pretty well on this quiz, but lots of people did fall into one mean little trap that I left in one question. (Sorry! I can be tricksy.) Here are the stats at the time of writing this post:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Entries: 436&lt;/td&gt;
&lt;td&gt;Average Score (Out of 4): 2.64&lt;/td&gt;
&lt;td&gt;Average Percentage: 66%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/grades.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Now for the fun stuff, let&amp;rsquo;s talk about answers!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="question-1"&gt;Question 1&lt;/h2&gt;
&lt;p&gt;1: How will the results of this query be ordered (and why)?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PersonID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;People&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Correct: 76% &lt;em&gt;Answer: No ordering is guaranteed in this case&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is very important to know: although the answers may come back ordered by PersonID in this case, you cannot count on that always being the case, and it could change at any point. Ordering of results is never guaranteed unless you explicitly use an ORDER BY in your query.&lt;/p&gt;
&lt;h2 id="question-2"&gt;Question 2&lt;/h2&gt;
&lt;p&gt;2: What will this ORDER BY do?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;People&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Correct: 90% &lt;em&gt;Answer: Order the results by the first column listed, PersonID&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Numbers used like this in the ORDER BY clause represent the column position. I was surprised that so many people knew the answer to this one, to be honest. It is a little bit troubling, because Microsoft calls out using numbers as positional representations in order by as &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017#best-practices"&gt;an anti-pattern that should be avoided&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, I confess, I personally do use this myself when I&amp;rsquo;m writing quick and dirty code (and sometimes forget to fix it, too).&lt;/p&gt;
&lt;h2 id="question-3"&gt;Question 3&lt;/h2&gt;
&lt;p&gt;3: What will this OFFSET / FETCH clause do?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;People&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FETCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Correct: 26% &lt;em&gt;Answer: This query will throw a syntax error&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Why? You can only use OFFSET with an ORDER BY.&lt;/p&gt;
&lt;p&gt;(This ain&amp;rsquo;t no TOP operator which doesn&amp;rsquo;t require ORDER BY, this is a &lt;em&gt;part&lt;/em&gt; of ORDER BY.)&lt;/p&gt;
&lt;p&gt;I asked this question to try to get a sense of how many people are currently using the OFFSET clause already in code and would pick out the goof based on familiarity. Seems like not many! That&amp;rsquo;s OK, but it&amp;rsquo;s good to know how this works for those times when it may come in handy.&lt;/p&gt;
&lt;h2 id="question-4"&gt;Question 4&lt;/h2&gt;
&lt;p&gt;4: What will this OFFSET clause do?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;People&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PersonID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROWS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Correct: 72% &lt;em&gt;Answer: Return all the rows except for the 10 with the lowest PersonIDs&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You are allowed to specify OFFSET without a FETCH NEXT. In this case, we are ordering by PersonID. We didn&amp;rsquo;t specify ascending or descending, so the default ascending sort order is used for the order. We are OFFSET-ing the first 10 rows ASC, so that&amp;rsquo;s the lowest 10 PersonIDs. We&amp;rsquo;ll get all the other rows, because we haven&amp;rsquo;t limited how many will be fetched.&lt;/p&gt;
&lt;h2 id="and-now-a-bad-joke"&gt;And Now, a Bad Joke&lt;/h2&gt;
&lt;p&gt;Unlike cursors, order by has finally &lt;em&gt;made fetch happen&lt;/em&gt;. (Sorry.)&lt;/p&gt;
&lt;p&gt;Nice work, folks!&lt;/p&gt;</description></item><item><title>New Courses: Extended Events, Parallelism, Indexes, and More</title><link>https://kendralittle.com/2018/06/22/new-courses-extended-events-parallelism-indexes-and-more/</link><pubDate>Fri, 22 Jun 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/06/22/new-courses-extended-events-parallelism-indexes-and-more/</guid><description>&lt;p&gt;It&amp;rsquo;s been a fun, busy spring and early summer. I have loads of new courses to share, and great stuff is coming up soon!&lt;/p&gt;
&lt;p&gt;A big thank you to all the SQLWorkbooks members who attended live events, or posted your comments and questions! Your questions are terrific, and you&amp;rsquo;ve made these events so much fun.&lt;/p&gt;
&lt;h2 id="sqlchallenge-courses"&gt;SQLChallenge Courses&lt;/h2&gt;
&lt;h2 id="sqlchallenge-create-an-extended-events-trace-55-minutes"&gt;&lt;a href="https://kendralittle.com/course/sqlchallenge-create-an-extended-events-trace/"&gt;SQLChallenge: Create an Extended Events Trace (55 minutes)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Follow the challenge script to reproduce a problem with Query Store in your test instance of SQL Server.&lt;/p&gt;
&lt;p&gt;Then, your challenge is to configure a trace that will capture the problem &amp;ndash; and also learn more about when the trace will capture an event, and when it won&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Challenge difficulty: This 200 level challenge will be pretty quick for folks who have configured Extended Events traces before. If you haven&amp;rsquo;t done that yet, it may take a little more time &amp;ndash; but it&amp;rsquo;s worth it! These traces can be extremely useful.&lt;/p&gt;
&lt;h2 id="design-the-best-index-for-one-year-wonders---sqlchallenge-50-minutes"&gt;&lt;a href="https://kendralittle.com/course/design-the-best-index-for-one-year-wonders-sqlchallenge/"&gt;Design the Best Index For One Year Wonders - SQLChallenge (50 minutes)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Can you reduce the logical reads as much as possible for the sample query using a disk based rowstore index?&lt;/p&gt;
&lt;p&gt;Challenge difficulty: This challenge comes with three levels of difficulty. Even the 200 level, creating a nonclustered index without using advanced features, is interesting in this case due to the nature of the query.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="sql-seminar-recordings"&gt;SQL Seminar Recordings&lt;/h2&gt;
&lt;h2 id="learn-indexing-by-solving-problems---sql-seminar---june-2018-7-hours-23-minutes"&gt;&lt;a href="https://kendralittle.com/course/learn-indexing-by-solving-problems-sql-seminar-june-2018/"&gt;Learn Indexing By Solving Problems - SQL Seminar - June 2018 (7 hours 23 minutes)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Learn to design and tune indexes by taking this set of eight indexing SQLChallenges!&lt;/p&gt;
&lt;p&gt;This course builds your skills at architecting disk based rowstore indexes in SQL Server, and teaches you how indexes work at the same time. The challenges in this course teach you about clustered and nonclustered indexes, filtered indexes, indexed views, and more.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="upcoming-live-sql-seminars"&gt;Upcoming Live SQL Seminars&lt;/h2&gt;
&lt;h2 id="conquer-blocking-and-isolation-levels"&gt;Conquer Blocking and Isolation Levels&lt;/h2&gt;
&lt;p&gt;Are your users getting wrong data back? Learn how to get correct data and minimize blocking in this eight hour seminar.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;July 11-12, 2018&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="query-tuning-jam-session"&gt;Query Tuning Jam Session&lt;/h2&gt;
&lt;p&gt;Sharpen your query tuning skills in this four hour course of live SQLChallenges and solutions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;July 30, 2018&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-decode-memory-pressure"&gt;How to Decode Memory Pressure&lt;/h2&gt;
&lt;p&gt;Learn to identify and monitor both external and internal memory pressure against SQL Server in this four hour seminar.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;August 14, 2018&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="learn-indexing-by-solving-problems---september-edition"&gt;Learn Indexing by Solving Problems - September Edition&lt;/h2&gt;
&lt;p&gt;Learn to architect disk-based rowstore indexes in eight hours of indexing challenges and solutions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;September 24-25, 2018&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="t-sql-school-select-seminars"&gt;T-SQL School: SELECT Seminars&lt;/h2&gt;
&lt;p&gt;Learn Transact-SQL by writing queries each week: Twelve one-hour sessions. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1PM – 2PM PDT, each Saturday through Aug 11, 2018&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>AVG() in TSQL: Watch Your Data Types</title><link>https://kendralittle.com/2018/06/21/avg-in-tsql-watch-your-datatypes/</link><pubDate>Thu, 21 Jun 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/06/21/avg-in-tsql-watch-your-datatypes/</guid><description>&lt;p&gt;This week&amp;rsquo;s Quizletter featured a quiz on using the AVG() function in SQL Server.&lt;/p&gt;
&lt;p&gt;I was inspired to write this quiz because I&amp;rsquo;ve been teaching &amp;ldquo;TSQL School&amp;rdquo; each week. When we covered aggregate functions, I remembered how tricksy AVG() can be.&lt;/p&gt;
&lt;h2 id="question-1-avg-of-1-and-1"&gt;Question 1: AVG of 1 and 1&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/avg-query-1-300x225.png"&gt;
&lt;/figure&gt;
&lt;p&gt;In question 1, we average a value on two rows: one and one.&lt;/p&gt;
&lt;p&gt;How did folks do on this question?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 91% - These folks guessed the answer would be: 1&lt;/li&gt;
&lt;li&gt;Incorrect: 9% - These folks almost all guessed the answer would be: 1.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This seems like a subtle difference, but the key to the answer is understanding what data type SQL Server will implicitly convert these numbers to. And data types matter a lot when it comes to the results you can get out of AVG. In this case, 1 will be implicitly converted to an INT data type.&lt;/p&gt;
&lt;h2 id="question-2-avg-of-1-and-2"&gt;Question 2: AVG of 1 and 2&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/avg-query-2-300x238.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s where the wacky fun begins: if I average two ints, one and two, I get back&amp;hellip; one!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;46% - YAY TEAM! Great work! This is bizarro, so good on you folks.&lt;/li&gt;
&lt;li&gt;54% - I feel your pain. Most of these folks guessed 1.5, a few guessed 1.500000&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What does this mean? Well, let&amp;rsquo;s look at an example with negative numbers to help get a bigger picture:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/avg-query-2-negative-numbers-300x223.png"&gt;
&lt;/figure&gt;
&lt;p&gt;When we round integers -1 and -2, we get -1.&lt;/p&gt;
&lt;h2 id="how-to-describe-this-behavior"&gt;How to Describe This Behavior&lt;/h2&gt;
&lt;p&gt;There are two different ways you can think about this behavior. Pick the one that is easier for you to remember.&lt;/p&gt;
&lt;p&gt;Description 1: SQL Server rounds integers &amp;ldquo;toward zero&amp;rdquo;. (When the average was positive, we got the &amp;lsquo;floor&amp;rsquo;. When the average was negative, we got the &amp;lsquo;ceiling&amp;rsquo;.)&lt;/p&gt;
&lt;p&gt;Description 2: It&amp;rsquo;s truncating the decimal bits.&lt;/p&gt;
&lt;p&gt;Extra credit: Guess which one of these descriptions came from me, and which one came from my computer scientist partner.&lt;/p&gt;
&lt;h2 id="question-3-mixing-in-a-cast"&gt;Question 3: Mixing in a CAST()&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/avg-query-3-293x300.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Aha! Now we&amp;rsquo;re getting fancy. We have a CAST function outside of the AVG function.&lt;/p&gt;
&lt;p&gt;The keys to this answer are that CAST will be run after the AVG function completes, and the AVG function is still returning 1, because &lt;em&gt;inside&lt;/em&gt; the AVG function, it sees the INT data type.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 36% - These cunning quizzers worked out that AVG would truncate the decimal bits and return 1, and that this would then be cast to 1.0&lt;/li&gt;
&lt;li&gt;Incorrect: 64% - Most folks guessed 1.5&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="question-4-move-that-cast-inside-the-avg"&gt;Question 4: Move That CAST() Inside the AVG()&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/avg-query-4-300x201.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Here we finally have an example where I am changing the data type inside the AVG, and we are casting to a numeric type with precision of three, scale of one. (One number past the decimally bit!)&lt;/p&gt;
&lt;p&gt;And, yeah, look at that, we get back a result with a scale of SIX.&lt;/p&gt;
&lt;p&gt;In fact, if you to the trouble to see what type we end up with here (like by selecting the results into a temp table and inspecting the data types), this is numeric(38,6). 38 is the highest precision you can get with numeric.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Correct: 37% - Clever rabbits!&lt;/li&gt;
&lt;li&gt;Incorrect: 63% - Most of these folks guessed 1.5, and &lt;em&gt;I do not blame you at all&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What&amp;rsquo;s up with this? Well, there&amp;rsquo;s a bit of info inside the &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/avg-transact-sql?view=sql-server-2017"&gt;documentation on AVG&lt;/a&gt;, but it&amp;rsquo;s about the decimal data type. Numeric and decimal are twins (but you want to use one or the other consistently, because of things like foreign keys). In the section on return types, it explains that the return type for decimal category (p, s) will be:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;decimal(38, s) divided by decimal(10, 0)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Plugging that formula into the numbers we&amp;rsquo;re working with in this question:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/avg-query-4-detail.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Yep, it checks out.&lt;/p&gt;
&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;Weird things like this are why &lt;a href="https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue"&gt;some folks say not to do calculations in the SQL language&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For times when you do need to do calculations in TSQL, remember to think about your data types&amp;ndash; both inside your functions, and outside.&lt;/p&gt;</description></item><item><title>Dear SQL DBA: Training Resources for SQL Newbies</title><link>https://kendralittle.com/2018/06/14/dear-sql-dba-training-resources-for-sql-newbies/</link><pubDate>Thu, 14 Jun 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/06/14/dear-sql-dba-training-resources-for-sql-newbies/</guid><description>&lt;p&gt;New to learning SQL Server? Get the scoop on free online resources to look up information, ask questions of community members, and learn SQL Server from the ground up.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;Subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;amp;isi=691797987&amp;amp;ius=googleplaymusic&amp;amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss#&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="video"&gt;Video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/4XsjcHIFZ7A?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Perks for My SQLPASS Summit Precon: Prevent Fake News in Your Data! Isolation Levels Demystified</title><link>https://kendralittle.com/2018/06/12/perks-for-my-sqlpass-summit-precon-prevent-fake-news-in-your-data-isolation-levels-demystified/</link><pubDate>Tue, 12 Jun 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/06/12/perks-for-my-sqlpass-summit-precon-prevent-fake-news-in-your-data-isolation-levels-demystified/</guid><description>&lt;p&gt;I&amp;rsquo;m proud, giddy, and just plain overly excited to be giving &lt;a href="http://www.pass.org/summit/2018/Sessions/Details.aspx?sid=78982"&gt;a pre conference session at the SQL PASS Summit in Seattle, Washington on November 5, 2018&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is going to be a fun, demo-packed day which will teach you skills you can use throughout your career as a developer, database administrator, or data professional.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Prevent-Fake-News-in-Your-Data-Isolation-Levels-Demystified.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="why-attend"&gt;Why Attend?&lt;/h2&gt;
&lt;p&gt;While features and tricks change from year to year (or even month to month), understanding isolation levels is critical for your long term future.&lt;/p&gt;
&lt;h2 id="the-session-prevent"&gt;&lt;strong&gt;The Session: Prevent &amp;lsquo;Fake News&amp;rsquo; in Your Data! Isolation Levels Demystified&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Are your users seeing bad data? If you&amp;rsquo;re using the default isolation level of read committed in SQL Server, chances are that sometimes your users get incorrect results. If NOLOCK hints lurk in your code, the odds are even higher that sometimes your customers see information that just isn&amp;rsquo;t right.&lt;/p&gt;
&lt;p&gt;In this day-long, demo packed session, you&amp;rsquo;ll learn why a single statement may read rows twice, miss rows entirely, or return combinations of data that never existed in the database &amp;ndash; and why that&amp;rsquo;s not a bug. You&amp;rsquo;ll learn what &amp;ldquo;read phenomena&amp;rdquo; are, which isolation levels are vulnerable to them, and the performance trade-offs which come from raising your isolation level to protect your users from bad data.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll see how isolation levels work with newer technologies such as columnstore indexes, In-Memory OLTP, and Always On Availability Groups. You&amp;rsquo;ll discover why version-based isolation levels can be awesome, and what you need to look out for with these isolation levels to avoid race conditions that produce&amp;ndash; you guessed it&amp;ndash; incorrect results.&lt;/p&gt;
&lt;p&gt;At the end of the day, we&amp;rsquo;ll pull together all this information into a guide. You&amp;rsquo;ll leave the seminar with the tools and knowledge to choose the right isolation levels for new and existing applications based on business and performance requirements.&lt;/p&gt;
&lt;h2 id="what-does-it-cost"&gt;What Does It Cost?&lt;/h2&gt;
&lt;p&gt;A single pre-conference session is $499. You can also &lt;a href="https://www.pass.org/summit/2018/RegisterNow.aspx"&gt;bundle pre-conference sessions with registration at the full Summit&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-perks"&gt;The Perks&lt;/h2&gt;
&lt;p&gt;Attendees at my pre-conference session will not only get all the demos we show live, and a download of the PDF of slides, but also&amp;hellip;.&lt;/p&gt;
&lt;h2 id="perk-watch-it-again-later"&gt;Perk: Watch It Again Later&lt;/h2&gt;
&lt;p&gt;Access to a recorded online session of my 8 hour seminar, &amp;ldquo;Conquer Blocking &amp;amp; Isolation Levels&amp;rdquo; for a full year.&lt;/p&gt;
&lt;p&gt;Want to revisit a topic and get the nitty gritty details? You&amp;rsquo;ll be able to watch anytime, online.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: the live pre-conference sessions at PASS aren't recorded for purchase anymore: however, you can buy recordings of "regular" sessions during the week from PASS in different formats.
&lt;/div&gt;
&lt;h2 id="perk-a-month-of-sqlchallenges"&gt;Perk: A Month of SQLChallenges!&lt;/h2&gt;
&lt;p&gt;For four weeks following the conference, I&amp;rsquo;ll be sending out &lt;a href="https://kendralittle.com/topics/sqlchallenges/"&gt;SQLChallenges&lt;/a&gt; on blocking and isolation level problems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attendees will get access to the problems and a chance to apply the skills they&amp;rsquo;ve learned.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ll share out sample solutions for the problem. All SQLChallenges support Q&amp;amp;A in the course pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="perk-follow-up-quizzes"&gt;Perk: Follow-Up Quizzes&lt;/h2&gt;
&lt;p&gt;Want even more learning? Following the SQLChallenges, attendees will get access to a series of four quizzes about blocking and isolation levels to confirm your knowledge.&lt;/p&gt;
&lt;p&gt;Combining this with the SQLChallenges will fully establish your new knowledge in place, getting you the most value for your dollar.&lt;/p&gt;
&lt;h2 id="register-here"&gt;Register Here&lt;/h2&gt;
&lt;p&gt;I hope to see you at the PASS Summit! &lt;a href="https://www.pass.org/summit/2018/RegisterNow.aspx"&gt;Sign up here to join my pre-conference session&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Two Free Sessions Next Week: Fighting Bad Data and Deadlocks</title><link>https://kendralittle.com/2018/06/07/two-free-sessions-next-week-fighting-bad-data-and-deadlocks/</link><pubDate>Thu, 07 Jun 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/06/07/two-free-sessions-next-week-fighting-bad-data-and-deadlocks/</guid><description>&lt;p&gt;I am excited and honored to be giving two free online sessions next week. Both events are sponsored by the fine folks over at &lt;a href="https://www.quest.com/"&gt;Quest Software&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-is-that-data-wrong-how-choosing-the-wrong-isolation-level-causes-bad-results"&gt;Why is That Data Wrong? How Choosing the Wrong Isolation Level Causes Bad Results&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Tuesday, June 12, Noon Pacific&lt;/strong&gt; &lt;strong&gt;&lt;a href="http://www.pass.org/24hours/2018/summitpreview/Schedule.aspx"&gt;24 Hours of PASS, Sponsored by Quest Software&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you haven&amp;rsquo;t thought much about isolation levels in SQL Server, chances are your applications can return inconsistent data to your users: data that looks completely wrong. If your user re-runs their report or reloads their screen, the data may look right the second time&amp;hellip; but after this happens, your customer feels that they can’t trust your data.&lt;/p&gt;
&lt;p&gt;In this session, you will learn why we have &amp;ldquo;isolation levels,&amp;rdquo; and how the read committed isolation level works by default in SQL Server. You&amp;rsquo;ll see how easy it is to make a query return inconsistent results using these default settings, and why this is allowed to happen. We&amp;rsquo;ll dig into an example where blocking causes a query to return &amp;ldquo;impossible&amp;rdquo; query results. You&amp;rsquo;ll leave the session with a fresh understanding of why choosing the right isolation level is critical to the success of your applications.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pass.org/24hours/2018/summitpreview/Registration.aspx"&gt;Register for this free event here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.pass.org/24hours/2018/summitpreview/Schedule.aspx"&gt;Check out more awesome sessions at the 24 Hours of PASS&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="dba-vs-deadlock-how-to-out-index-a-deadly-blocking-scenario"&gt;DBA vs Deadlock: How to Out-Index a Deadly Blocking Scenario&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Thursday, June 14,&lt;/strong&gt; &lt;strong&gt;8:30 AM Pacific &lt;a href="https://www.quest.com/event/-dba-vs-deadlock-how-to-outindex-a-deadly-blocking-scenario8131969"&gt;Sponsored by Quest Software&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Deadlocks strike fear into the hearts of even seasoned DBAs — but they don’t have to!&lt;/p&gt;
&lt;p&gt;In this session, you’ll get the code to cause a sample deadlock in SQL Server. You’ll see how to interpret the deadlock graph to find out where the conflict lies, and how to design an index to make the deadlock disappear. You’ll leave the session with the steps you need to confidently tackle future deadlocks.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.quest.com/event/-dba-vs-deadlock-how-to-outindex-a-deadly-blocking-scenario8131969"&gt;Register for this free online session here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;See you next week!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Row Width Impact on Version Store Usage under Snapshot Isolation</title><link>https://kendralittle.com/2018/05/28/row-width-impact-on-version-store-usage-under-snapshot-isolation/</link><pubDate>Mon, 28 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/28/row-width-impact-on-version-store-usage-under-snapshot-isolation/</guid><description>&lt;p&gt;A question came up in my webcast today on the topic of Snapshot and Read Committed Snapshot Isolation - what impact will enabling these have on my SQL Server instance?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Wide-table-max-record-size-is-much-larger.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I talked a bit about how, for tempdb, this can vary widely depending on the number of updates and deletes running against the instance. (This is a simplification, there is more overhead, but this is often the biggest component.)&lt;/p&gt;
&lt;p&gt;But after the webcast, I realized that the impact on the version store isn&amp;rsquo;t simply on the &lt;em&gt;number&lt;/em&gt; of updates and deletes run. It will also vary based on the width of your rows &amp;ndash; how many columns are in the table, what data types the columns have, and what data you have in the table.&lt;/p&gt;
&lt;h2 id="even-if-you-change-one-very-small-column-the-entire-row-is-versioned---sort-of"&gt;Even If You Change One Very Small Column, the Entire Row Is Versioned - &lt;em&gt;sort of&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;My favorite thing about SQL Server is that it includes rich tools to let us learn how the engine works by setting up simple demos. It&amp;rsquo;s truly awesome.&lt;/p&gt;
&lt;p&gt;So I went to work to demonstrate row width impact on the version store &amp;ndash; when only a &lt;em&gt;tiny bit column&lt;/em&gt; is changed in the row.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how I did the test:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I created two tables, dbo.Narrow and dbo.Wide. They each each have a bit column named bitsy, along with some other columns.&lt;/li&gt;
&lt;li&gt;I inserted one row in each table, but I put a lot &lt;em&gt;more&lt;/em&gt; data into the row in dbo.Wide.&lt;/li&gt;
&lt;li&gt;I allowed snapshot isolation on the database&lt;/li&gt;
&lt;li&gt;I began a transaction in another session under snapshot isolation and left the transaction open (so version store cleanup wouldn&amp;rsquo;t kick in while I looked around)&lt;/li&gt;
&lt;li&gt;I updated the bit column named bitsy for the single row in each table, thereby generating a row-version in tempdb for each table&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The code I ran to test this &lt;a href="https://gist.github.com/LitKnd/9ee95888e4409342292831736ab0572b"&gt;is here&lt;/a&gt;, if you&amp;rsquo;d like to play around with it.&lt;/p&gt;
&lt;h2 id="the-row-in-dbonarrow-is-38-bytes-of-in-row-data"&gt;The Row in dbo.Narrow Is 38 Bytes of In-Row Data&lt;/h2&gt;
&lt;p&gt;I measured the width of the largest row in dbo.Narrow using sys.dm_db_index_physical_stats. It only has one row, so the max width IS our row width. It&amp;rsquo;s a lil bitty 38 bytes.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Narrow-table-max-record-size-is-38-bytes.png"&gt;
&lt;/figure&gt;
&lt;h2 id="the-row-in-dbowide-is-8054-bytes-of-in-row-data-and-8012-bytes-off-row"&gt;The Row in dbo.Wide Is 8,054 Bytes of In-Row Data, and 8,012 Bytes Off Row&lt;/h2&gt;
&lt;p&gt;On the other side of the scale is dbo.Wide. This takes up 8,050 of in-row data (this happened because the &amp;lsquo;j&amp;rsquo; column is a char column, which is fixed width). It also is using 8,012 bytes of LOB_DATA storage, because I used the REPLICATE function to put a lot of garbage into the k column in dbo.Wide.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Wide-table-max-record-size-is-much-larger.png"&gt;
&lt;/figure&gt;
&lt;h2 id="lets-look-at-the-version-store"&gt;Let&amp;rsquo;s Look at the Version Store!&lt;/h2&gt;
&lt;p&gt;We can query the version store through sys.dm_tran_version_store. Querying this in detail on a production system may not be great if there are a lot of versions, but this is an idle test instance and I&amp;rsquo;ve only updated two rows.&lt;/p&gt;
&lt;p&gt;There are two rows in my version store. The Narrow table has 24 bytes of versioning data, the Wide table has 8,040 bytes of versioning data.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Version-store-size-for-narrow-and-wide-tables.png"&gt;
&lt;/figure&gt;
&lt;h2 id="observation-1-my-whole-row-was-versioned-except-for-the-lob-data"&gt;Observation 1: My Whole Row Was Versioned &lt;em&gt;except&lt;/em&gt; for the LOB Data&lt;/h2&gt;
&lt;p&gt;Large object data stored on LOB pages, like that in my NVARCHAR(MAX) column, can be versioned. Snapshot Isolation and Read Committed Snapshot Isolation work with LOB data too, and it&amp;rsquo;s easy to verify that that they &lt;em&gt;can&lt;/em&gt; be versioned by updating the column named &amp;lsquo;k&amp;rsquo; in this demo.&lt;/p&gt;
&lt;p&gt;But in this case, I don&amp;rsquo;t see them in the version store.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s awesome&amp;ndash; because I didn&amp;rsquo;t update the column that&amp;rsquo;s stored on LOB pages! I only updated a bit type column on that row. SQL Server is being clever about this.&lt;/p&gt;
&lt;h2 id="observation-2-my-versioned-rows-are-14-bytes-smaller"&gt;Observation 2: My Versioned Rows Are 14 Bytes Smaller&lt;/h2&gt;
&lt;p&gt;Comparing the size of my row-versions with the rows in the table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dbo.Narrow: 38 bytes in the table row, 24 bytes in the row version = 14 bytes difference&lt;/li&gt;
&lt;li&gt;dbo.Wide: 8,054 bytes of in-row data in the table row, 8,040 bytes in the version store = 14 bytes difference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That 14 bytes is a transaction timestamp/pointer piece of information in row of the data table itself that is an additional part of the overhead of row versioning &amp;ndash; but it doesn&amp;rsquo;t have to be copied into tempdb as well.&lt;/p&gt;
&lt;h2 id="summing-up-wider-rows-will-generally-mean-more-tempdb-usage-for-versioning"&gt;Summing Up: Wider Rows Will Generally Mean More tempdb Usage for Versioning&lt;/h2&gt;
&lt;p&gt;Even if you&amp;rsquo;re just updating one tiny column in your table, the entire row will be versioned &amp;ndash; with one important exception.&lt;/p&gt;
&lt;p&gt;My testing shows that data stored on LOB pages isn&amp;rsquo;t appearing in the version store unless I modify that data itself (not simply modifying another column in the row). Note: I haven&amp;rsquo;t found this explicitly documented while searching, and I only tested this against SQL Server 2017, so there may well be times when this is not the case&amp;ndash; but it does make sense that SQL Server could do this quite elegantly for LOB pages.&lt;/p&gt;
&lt;h2 id="what-should-i-do-if-i-am-considering-enabling-snapshot-isolation"&gt;What Should I Do if I Am Considering Enabling Snapshot Isolation?&lt;/h2&gt;
&lt;p&gt;If you have the ability to load test or run a &amp;lsquo;replay&amp;rsquo; workload outside of your production environment, that&amp;rsquo;s absolutely the best bet.&lt;/p&gt;
&lt;p&gt;If that isn&amp;rsquo;t realistic in your world, you can baseline performance on your current production workload, then test allowing snapshot isolation against the database before anything uses it at all. Versioning will still take place, and you can compare performance with your established baseline.&lt;/p&gt;
&lt;h2 id="want-to-learn-more-about-transaction-isolation"&gt;Want to Learn More About Transaction Isolation?&lt;/h2&gt;
&lt;p&gt;Check out my &lt;a href="https://kendralittle.com/topics/locking-and-blocking/"&gt;free online courses on locking and blocking in SQL Server&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Code: Fixing a Filtered Index Which is Causing Data Modifications to Fail</title><link>https://kendralittle.com/2018/05/23/code-fixing-a-filtered-index-which-is-causing-data-modifications-to-fail/</link><pubDate>Wed, 23 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/23/code-fixing-a-filtered-index-which-is-causing-data-modifications-to-fail/</guid><description>&lt;p&gt;This question came up in a webcast recently: if a filtered index is causing data modifications to fail, does disabling the filtered index fix the problem?&lt;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t 100% sure &amp;ndash; I couldn&amp;rsquo;t remember the last time I&amp;rsquo;d tried, if I ever had. So&amp;hellip;.&lt;/p&gt;
&lt;h2 id="lets-test-it"&gt;Let&amp;rsquo;s Test It!&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s reproduce the problem: we&amp;rsquo;ll create a filtered index on a table, then set up a session who can&amp;rsquo;t read from it due to an ANSI_SETTINGS conflict. (A list of required SET OPTIONS for filtered indexes is &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/create-index-transact-sql?view=sql-server-2017#filtered-indexes"&gt;documented here&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="heres-my-filtered-index"&gt;Here&amp;rsquo;s My Filtered Index&lt;/h2&gt;
&lt;p&gt;I created this in the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters sample database&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_SalesOrders_filtered_IsUndersupplyBackordered_OrderDate_INCLUDES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OrderID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SalespersonPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PickedByPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ContactPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BackorderOrderID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpectedDeliveryDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerPurchaseOrderNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IsUndersupplyBackordered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeliveryInstructions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PickingCompletedWhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditedBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IsUndersupplyBackordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="now-lets-make-our-session-incompatible-with-the-index"&gt;Now, Let&amp;rsquo;s Make Our Session Incompatible with the Index&lt;/h2&gt;
&lt;p&gt;All I have to do to make an insert fail is violate one of those required ANSI settings in my session.&lt;/p&gt;
&lt;p&gt;Here we go!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ANSI_NULLS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRANSACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SalespersonPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PickedByPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ContactPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BackorderOrderID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpectedDeliveryDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerPurchaseOrderNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IsUndersupplyBackordered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeliveryInstructions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PickingCompletedWhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditedBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SalespersonPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PickedByPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContactPersonID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BackorderOrderID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExpectedDeliveryDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerPurchaseOrderNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsUndersupplyBackordered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeliveryInstructions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PickingCompletedWhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastEditedBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="this-results-in-error-1934"&gt;This Results in Error 1934&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 1934, Level 16, State 1, Line 25
INSERT failed because the following SET options have incorrect settings: &amp;lsquo;ANSI_NULLS&amp;rsquo;. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="now-to-disable-the-filtered-index"&gt;Now to Disable the Filtered Index&lt;/h2&gt;
&lt;p&gt;I suck all the pages out of the filtered index, leaving only the metadata behind:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_SalesOrders_filtered_IsUndersupplyBackordered_OrderDate_INCLUDES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DISABLE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now, when I retry my insert&amp;hellip;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(1 row affected)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It worked! As long as this filtered index is disabled, the insert works again for the session with the incompatible ANSI_NULLS setting.&lt;/p&gt;
&lt;h2 id="personally-id-rather-drop-the-filtered-index"&gt;Personally, I&amp;rsquo;d Rather Drop the Filtered Index&lt;/h2&gt;
&lt;p&gt;Rebuilding the filtered index will cause this problem to happen again &amp;ndash; until all sessions modifying the table have the required se ssion settings in place.&lt;/p&gt;
&lt;p&gt;So to prevent actual rebuilds, I&amp;rsquo;d rather drop the index until everything is in order for the index to be recreated.&lt;/p&gt;</description></item><item><title>Free Session! DBA vs Deadlock: How to Out-Index a Deadly Blocking Scenario</title><link>https://kendralittle.com/2018/05/22/free-session-dba-vs-deadlock-how-to-out-index-a-deadly-blocking-scenario/</link><pubDate>Tue, 22 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/22/free-session-dba-vs-deadlock-how-to-out-index-a-deadly-blocking-scenario/</guid><description>&lt;h2 id="dba-vs-deadlock-how-to-out-index-a-deadly-blocking-scenario"&gt;DBA vs Deadlock: How to Out-Index a Deadly Blocking Scenario&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;June 14, 2018&lt;/strong&gt; &lt;strong&gt;8:30 AM – 9:30 AM PST&lt;/strong&gt; &lt;em&gt;&amp;lt;- This is past, but no worries, it was recorded&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Deadlocks strike fear into the hearts of even seasoned DBAs — but they don’t have to!&lt;/p&gt;
&lt;p&gt;In this session, you’ll get the code to cause a sample deadlock in SQL Server. You’ll see how to interpret the deadlock graph to find out where the conflict lies, and how to design an index to make the deadlock disappear.&lt;/p&gt;
&lt;p&gt;You’ll leave the session with the steps you need to confidently tackle future deadlocks.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.quest.com/event/-dba-vs-deadlock-how-to-outindex-a-deadly-blocking-scenario8131969"&gt;Watch the recording of this free online session here.&lt;/a&gt;&lt;/p&gt;</description></item><item><title>What is Deferred Name Resolution, and How Can It Go Wrong?</title><link>https://kendralittle.com/2018/05/21/what-is-deferred-name-resolution-and-how-can-it-go-wrong/</link><pubDate>Mon, 21 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/21/what-is-deferred-name-resolution-and-how-can-it-go-wrong/</guid><description>&lt;p&gt;I got a question recently about why a particular bit of code was failing when running.&lt;/p&gt;
&lt;p&gt;My first thought: oh, that&amp;rsquo;s probably related to&amp;hellip; &lt;em&gt;whatsitcalled&lt;/em&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Deferred-name-resolution.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;You know, &lt;em&gt;whatsitcalled&lt;/em&gt;, one of those features you notice just often enough so that it&amp;rsquo;s name doesn&amp;rsquo;t come to mind immediately.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s deferred.&lt;/p&gt;
&lt;p&gt;In this case, it was actually named &amp;ldquo;&lt;a href="https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms190686(v=sql.105)"&gt;Deferred Name Resolution&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="deferred-name-resolution-lets-you-create-a-procedure-referencing-something-that-doesnt-exist"&gt;Deferred Name Resolution Lets You Create a Procedure Referencing Something That Doesn&amp;rsquo;t Exist&lt;/h2&gt;
&lt;p&gt;In this case, I&amp;rsquo;m creating a temporary stored procedure (out of laziness, it means I don&amp;rsquo;t have to clean up a quick demo) -&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbdoesnotexist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;someproc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The database dbdoesnotexist does NOT exist, but I&amp;rsquo;m still allowed to create the procedure.&lt;/p&gt;
&lt;p&gt;When I do so, I get an informational message:&lt;/p&gt;
&lt;p&gt;The module &amp;lsquo;#test&amp;rsquo; depends on the missing object &amp;lsquo;dbdoesnotexist.dbo.someproc&amp;rsquo;. The module will still be created; however, it cannot run successfully until the object exists.&lt;/p&gt;
&lt;p&gt;This can be useful in some cases where you&amp;rsquo;ll be querying a table or procedure that may not exist all the time, but which will exist when a certain code block is run.&lt;/p&gt;
&lt;h2 id="you-cant-always-count-on-deferred-name-resolution"&gt;You Can&amp;rsquo;t Always Count on Deferred Name Resolution&lt;/h2&gt;
&lt;p&gt;What if our code refers to something that &lt;em&gt;may&lt;/em&gt; exist, but isn&amp;rsquo;t accessible?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a slightly different code sample:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offlinedb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offlinedb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offlinedb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;someproc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="this-results-in-error-942"&gt;This Results in Error 942&lt;/h2&gt;
&lt;p&gt;Creating the procedure fails in this case. The error given is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 942, Level 14, State 4, Procedure #test, Line 5 [Batch Start Line 17]
Database &amp;lsquo;offlinedb&amp;rsquo; cannot be opened because it is offline.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If I set the empty database &amp;ldquo;offlinedb&amp;rdquo; to be online, then deferred name resolution works and I can create #test. If I drop &amp;ldquo;offlinedb&amp;rdquo;, same thing&amp;ndash; no problems.&lt;/p&gt;
&lt;p&gt;But while offlinedb exists in an offline state, I get error 942 at the time I attempt to create the procedure.&lt;/p&gt;
&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;Little quirks like this are a good argument to configure test and pre-production/staging environments in ways that mirror production as much as possible.&lt;/p&gt;
&lt;p&gt;And if you think you might run into this situation, it might be worth using a bit of Dynamic SQL to avoid it!&lt;/p&gt;</description></item><item><title>Dear SQL DBA: Dealing With a Lack of Control</title><link>https://kendralittle.com/2018/05/18/dear-sql-dba-dealing-with-a-lack-of-control/</link><pubDate>Fri, 18 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/18/dear-sql-dba-dealing-with-a-lack-of-control/</guid><description>&lt;p&gt;This week I discuss a question that I&amp;rsquo;ve gotten in many forms over the years - a lot of the scenarios are so specific that it&amp;rsquo;s hard to keep them anonymous, but they can be generalized as a bigger problem: how do I deal with being responsible for things that I can&amp;rsquo;t fully control?&lt;/p&gt;
&lt;p&gt;DBAs have huge responsibilities, so this is a common, frustrating scenario. In this episode, I talk about a few times that I&amp;rsquo;ve experienced this in my own life, what techniques didn&amp;rsquo;t work, and what strategies were more effective.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subscribe:&lt;/strong&gt; If you’d rather listen on the go, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;subscribe on iTunes&lt;/a&gt; or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss#&lt;/a&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/xKEbFOwoA3Q?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h1 id="my-notes-for-the-session"&gt;My notes for the session&lt;/h1&gt;
&lt;h2 id="everyday-dilbert-moments"&gt;Everyday Dilbert Moments&lt;/h2&gt;
&lt;p&gt;The Bug Nobody Caused&lt;/p&gt;
&lt;p&gt;Committing to an SLA I couldn&amp;rsquo;t meet&lt;/p&gt;
&lt;p&gt;The Case of the Weak KPIs&lt;/p&gt;
&lt;h2 id="techniques-that-havent-worked-for-me"&gt;Techniques That Haven&amp;rsquo;t Worked for Me&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;No&amp;rdquo; &amp;ldquo;This is not my responsibility&amp;rdquo; &amp;ldquo;-TICKET CLOSED&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If other people keep tagging you and saying &amp;ldquo;you&amp;rsquo;re it&amp;rdquo;, just saying &amp;ldquo;not it&amp;rdquo; or &amp;ldquo;I&amp;rsquo;m not playing this game&amp;rdquo; doesn&amp;rsquo;t stop them from continuing.&lt;/p&gt;
&lt;h2 id="techniques-that-can-work"&gt;Techniques That Can Work&lt;/h2&gt;
&lt;h2 id="first-chill"&gt;First: Chill&lt;/h2&gt;
&lt;p&gt;Being responsible for things you can&amp;rsquo;t control frequently triggers stress&lt;/p&gt;
&lt;p&gt;Stress triggers knee-jerk responses&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Knee jerk responses don&amp;rsquo;t go anywhere&lt;/li&gt;
&lt;li&gt;Not taken seriously&lt;/li&gt;
&lt;li&gt;Generally don&amp;rsquo;t have thoughtful, supporting data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need to be more strategic&lt;/p&gt;
&lt;h2 id="find-a-way-to-de-personalize-the-issue"&gt;Find a Way to De-Personalize the Issue&lt;/h2&gt;
&lt;p&gt;Think outside your current role&lt;/p&gt;
&lt;p&gt;If you were the CTO of the company, what would you want to see happen?&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t limit your &lt;em&gt;thinking&lt;/em&gt; to what you can do now&lt;/p&gt;
&lt;h2 id="do-what-you-can"&gt;Do What You Can&lt;/h2&gt;
&lt;p&gt;Outline and document the limitations to what you&amp;rsquo;ve done&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Here&amp;rsquo;s what I can do for you&amp;rdquo; (even if it&amp;rsquo;s to try to help escalate)&lt;/p&gt;
&lt;h2 id="sometimes-sketch-out-an-approach-to-narrow-the-gap"&gt;Sometimes&amp;hellip; Sketch Out an Approach to Narrow the Gap&lt;/h2&gt;
&lt;p&gt;Even if it&amp;rsquo;s not you who could carry it out&lt;/p&gt;
&lt;p&gt;Ask for help to narrow the gap&lt;/p&gt;
&lt;p&gt;Who do you think could help make this happen?&lt;/p&gt;
&lt;h2 id="raise-the-flag-high-when-needed"&gt;Raise the Flag High When Needed&lt;/h2&gt;
&lt;p&gt;Security risks&lt;/p&gt;
&lt;p&gt;Risks of data loss&lt;/p&gt;
&lt;p&gt;Ethics breaches&lt;/p&gt;</description></item><item><title>Fake News about Auto Parameterization/Simple Parameterization</title><link>https://kendralittle.com/2018/05/04/fake-news-about-auto-parameterization-simple-parameterization/</link><pubDate>Fri, 04 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/04/fake-news-about-auto-parameterization-simple-parameterization/</guid><description>&lt;p&gt;I saw a question on Twitter today that took me down a little rabbit hole. And when I go down rabbit holes, I like to blog about it! There&amp;rsquo;s a TLDR at the bottom of this post if you&amp;rsquo;re short on time.&lt;/p&gt;
&lt;p&gt;Grant Fritchey &lt;a href="https://twitter.com/GFritchey/status/992428226491363328"&gt;asked&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simple parameterization on a trivial query with a WHERE clause. Supply a different value, new plan, also parameterized. The old plan was not reused.&lt;/p&gt;
&lt;p&gt;I thought simple parameterization lead to plan reuse?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="simple-parameterization-leads-to-insanity"&gt;Simple Parameterization Leads to Insanity&lt;/h2&gt;
&lt;p&gt;The thing about simple parameterization is that it&amp;rsquo;s not simple.&lt;/p&gt;
&lt;p&gt;This is also known as auto-parameterization, and sometimes it&amp;rsquo;s not automatic &amp;ndash; in other words, sometimes it looks like it happens, but it doesn&amp;rsquo;t actually happen.&lt;/p&gt;
&lt;p&gt;In Klaus Aschenbrenner&amp;rsquo;s blog post, &amp;ldquo;&lt;a href="https://www.sqlpassion.at/archive/2015/04/27/the-pain-of-simple-parameterization-in-sql-server/"&gt;The Pain of Simple Parameterization&lt;/a&gt;&amp;rdquo;, he wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In general SQL Server only auto parameterizes your SQL statements if you deal with a so-called &lt;strong&gt;Safe Execution Plan&lt;/strong&gt;: regardless of the provided input parameter values, the query must always lead to the same execution plan.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are times when SQL Server just doesn&amp;rsquo;t think it&amp;rsquo;s safe to simply parameterize your query, and that can be SUPER confusing when you&amp;rsquo;re looking at queries.&lt;/p&gt;
&lt;h2 id="heres-what-simple-parameterization-looks-like-when-it-works"&gt;Here&amp;rsquo;s What Simple Parameterization Looks Like When It Works&lt;/h2&gt;
&lt;p&gt;I run two these two statements against the BabbyNames database&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;76682&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;86055&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the actual execution plan, I see that the literal FirstNameId values have been replaced with @1.&lt;/p&gt;
&lt;p&gt;Further, in the properties of the leftmost operator on the plan, I see that StatementParameterization type = 2.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/execution-plan-simple-parameterization-1024x326.png"&gt;
&lt;/figure&gt;
&lt;p&gt;In Query Store and the plan cache, the text for my query gets recorded as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That single plan is show as having two executions. In other words, it&amp;rsquo;s re-used.&lt;/p&gt;
&lt;h2 id="simple-parameterization-sometimes-doesnt-happen-but-looks-kinda-like-it-did-in-your-execution-plan"&gt;Simple Parameterization Sometimes Doesn&amp;rsquo;t Happen&amp;hellip; but Looks Kinda Like It Did in Your Execution Plan&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s change our query a little:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Grant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Kendra&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When I run these new queries, here&amp;rsquo;s what my actual execution plan looks like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/execution-plan-is-this-simple-parameterization-1024x432.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Hmmmm&amp;hellip; this is different! I&amp;rsquo;ve got the @1 again in my query text, and it&amp;rsquo;s even in the parameter list on the left.&lt;/p&gt;
&lt;p&gt;But notice that this time, StatementParameterizationType is 0.&lt;/p&gt;
&lt;p&gt;Last time, that was set to 2!&lt;/p&gt;
&lt;h2 id="this-didnt-really-get-parameterized"&gt;This Didn&amp;rsquo;t Really Get Parameterized&lt;/h2&gt;
&lt;p&gt;If I look in Query Store and my query plan cache, I find two queries and two plans.&lt;/p&gt;
&lt;p&gt;The queries are formatted differently, they look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Grant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Kendra&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parameter didn&amp;rsquo;t make it in there at all.&lt;/p&gt;
&lt;h2 id="tldr-sometimes-it-looks-like-something-has-been-simple-parameterized-in-an-actual-execution-plan-but-it-hasnt"&gt;TLDR: Sometimes, It Looks Like Something Has Been Simple Parameterized in an Actual Execution Plan, but It Hasn&amp;rsquo;t&lt;/h2&gt;
&lt;p&gt;Just because I see an @1 being substituted in for a literal value in that text hint at the top of a plan doesn&amp;rsquo;t mean that simple parameterization has actually happened.&lt;/p&gt;
&lt;p&gt;And for the record, I&amp;rsquo;m not sure that this is the exact scenario Grant was asking about, because my second example here isn&amp;rsquo;t technically a &amp;rsquo;trivial&amp;rsquo; plan. But I do think that this is one of many reasons to use &lt;em&gt;explicit&lt;/em&gt; parameterization practices, and not to rely on simple or auto-parameterization, because it just doesn&amp;rsquo;t work in many cases.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to play around with these examples, &lt;a href="https://gist.github.com/LitKnd/896c329e819e63f45251f2ba83ce7ad5"&gt;the code is in this gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And thank you Grant for posting this question, I needed it to get me out of a blogging dry spell!&lt;/p&gt;</description></item><item><title>Dear SQL DBA: Do DBAs Need a College Degree?</title><link>https://kendralittle.com/2018/05/03/dear-sql-dba-do-dbas-need-a-college-degree/</link><pubDate>Thu, 03 May 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/05/03/dear-sql-dba-do-dbas-need-a-college-degree/</guid><description>&lt;p&gt;Our question this week comes from a database administrator who&amp;rsquo;s excited to be on a healthy career path, building their work experience, getting certified, and working with a more experienced mentor.&lt;/p&gt;
&lt;p&gt;But they&amp;rsquo;re worried: will lacking a college degree block their career growth down the line?&lt;/p&gt;
&lt;p&gt;I talk about my experiences helping managers hire DBAs, and also check out current job listings in three locations in the United States to answer the question.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subscribe:&lt;/strong&gt; If you’d rather listen on the go, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;amp;isi=691797987&amp;amp;ius=googleplaymusic&amp;amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss#&lt;/a&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/xZgsCkvKGbI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="intrigued-by-the-free-turkey-i-mention"&gt;Intrigued by the Free Turkey I Mention?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a direct link to &lt;a href="https://thenavisway.csod.com/ats/careersite/JobDetails.aspx?id=506"&gt;the fun-looking DBA job in Bend, Oregon&lt;/a&gt;. This post is not sponsored by NAVIS  :)&lt;/p&gt;
&lt;h2 id="transcript"&gt;Transcript&lt;/h2&gt;
&lt;p&gt;Welcome to Dear SQL DBA: do database administrators need college degrees? My name is Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;h2 id="this-weeks-question"&gt;This Week&amp;rsquo;s Question&lt;/h2&gt;
&lt;p&gt;All right, this week&amp;rsquo;s question for the podcast came from a user who said: I&amp;rsquo;m currently finishing my Oracle DBA certification path and I love it, and I&amp;rsquo;m very excited to start my career as a DBA. There&amp;rsquo;s a Senior DBA and my current place of employment who is going to mentor me as well. I have fourteen months of hands-on experience with SQL Server and Oracle, but here&amp;rsquo;s the thing: I don&amp;rsquo;t have a college degree. I have about 60 hours of college credits. Do you think my education will hinder my chances of getting a job as a DBA even with my certifications and hands-on experience?&lt;/p&gt;
&lt;p&gt;This is an interesting question, and I don&amp;rsquo;t know about you, but I do have a college degree &amp;ndash; I have a bachelor&amp;rsquo;s degree and I have a master&amp;rsquo;s degree. But my bachelor&amp;rsquo;s degree is a super fruity humanities degree, and my master&amp;rsquo;s degree is in philosophy. But I got those a long time ago, so I was like um okay 60 hours, how much of a college degree is that? I didn&amp;rsquo;t even remember. I looked it up, typically a bachelor&amp;rsquo;s degree is a hundred and twenty credit hours. That does usually take four years full-time, of course we all know folks who have done it in a longer time, right?&lt;/p&gt;
&lt;p&gt;I know folks who&amp;rsquo;ve done it quicker as well, but of course if our questioner has 60 hours and it generally takes about 120 hours, then yeah that would be a lot of work &amp;ndash; especially if you&amp;rsquo;re working full-time and are trying to finish it up at night, that would not be a trivial thing to do.&lt;/p&gt;
&lt;p&gt;How much of a hindrance is that going to be?&lt;/p&gt;
&lt;h2 id="anecdotally-i-do-know-quite-a-few-dbas-who-are-gainfully-employed-and-who-dont-have-college-degrees"&gt;Anecdotally, I Do Know Quite a Few DBAs Who Are Gainfully Employed and Who Don&amp;rsquo;t Have College Degrees&lt;/h2&gt;
&lt;p&gt;Anecdotally, I know it can happen out there&amp;ndash; but the question is how much will this hinder me?&lt;/p&gt;
&lt;p&gt;I decided to take a look and sample some job listings out there and just look at what are the listings saying. I looked at listings in a couple of different areas: I looked first at some job listings near me. I live in Oregon in the Pacific northwest, and I was curious: around me what are people saying about DBA job positions, what do they want?&lt;/p&gt;
&lt;p&gt;Because of course, a job listing is a lot like an ad on a dating site: you may not end up with your ideal match.&lt;/p&gt;
&lt;h2 id="some-listings-around-portland-oregon-usa"&gt;Some Listings Around Portland, Oregon, USA&lt;/h2&gt;
&lt;p&gt;But in terms of what listings are saying, there&amp;rsquo;s a job near me at a health plan. I found this job online, but I was at a SQL Server group in my area recently and I met someone there who works at this place, and talked a little bit about the job as well! For the DBA job, they would like to have it a bachelor&amp;rsquo;s degree in computer science information systems or similar or an equivalent combination of Education and experience. That position is focused on SQL Server. There&amp;rsquo;s also a software company downtown, and I know a lot of bright folks who&amp;rsquo;ve worked there, and this software company &amp;ndash; they don&amp;rsquo;t list any degree requirements at all. They want five years of experiences as a DBA, and then if you&amp;rsquo;ve used lots of different technologies, they&amp;rsquo;re really interested in you, too. They want a DBA but they also want someone who&amp;rsquo;s interested in different NOSQL technologies and learning lots of different ways to store data.&lt;/p&gt;
&lt;p&gt;Some more jobs around me in the Northwest: there&amp;rsquo;s a database developer at an IT and analytics firm and they again said we want a bachelor&amp;rsquo;s in engineering or computer science &amp;ndash; and folks when they&amp;rsquo;re listing degrees they are listing degree areas. They aren&amp;rsquo;t just saying a bachelors, they&amp;rsquo;re really generally saying computer science or related area, or equivalent experience. There&amp;rsquo;s a gift card startup around here too that&amp;rsquo;s looking for a DBA slash system engineer. They want you to also be in their system and engineering team, there&amp;rsquo;s some app support, and again bachelor&amp;rsquo;s degree in computer science or related field or equivalent experience.&lt;/p&gt;
&lt;p&gt;A lot of the companies in the Pacific northwest just say in the job listing &amp;ldquo;or equivalent&amp;rdquo;. They seem to be really open to people who have the right experience if, you don&amp;rsquo;t have a degree it&amp;rsquo;s no big deal.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a tech company in Bend, Oregon &amp;ndash; and if you&amp;rsquo;ve never been to Bend, Oregon it is a lovely place! I go there to ride bikes sometimes. It&amp;rsquo;s a wonderful place to visit. They want somebody with a four-year degree in computer science or equivalent, and their job description actually mentions that they give all their employees free turkeys every year on Thanksgiving. You can also have pie if you don&amp;rsquo;t want the turkey. They celebrate Halloween and they mention this in the job description. You know, when you&amp;rsquo;re looking at job descriptions even when you&amp;rsquo;re not looking for yourself, it&amp;rsquo;s a little depressing &amp;ndash; but then occasionally you come across these little gems where you&amp;rsquo;re like, oh you actually seem like a fun company! And they&amp;rsquo;re saying you &amp;ldquo;or equivalent experience.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;There is also a cloud software company in Oregon, they are hiring people remote. I think they were headquartered in Texas, but they have the ad listed in Oregon so that it would come up for candidates here, since it is a remote job. And they wanted a lot of cloud experience as well as database experience, but again no degree listed. There were some desirable AWS certifications and the like in there of course, but it generally may not take you four years of going to school full-time to get an AWS certification. Maybe a little bit easier there.&lt;/p&gt;
&lt;p&gt;In my area in the Pacific Northwest in the United States, it looks like there&amp;rsquo;s a lot of &amp;ldquo;or equivalent.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="senior-dba-listings-around-washington-dc"&gt;Senior DBA Listings Around Washington, DC&lt;/h2&gt;
&lt;p&gt;OK, so I said &amp;ndash; all right, my guess is just from having consulted with people around the country and around the world, that there are gonna be different job climates in different locations where some are more restricted.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m gonna look at some listings in Washington DC, because it seems like a pretty conservative area. I lived there for a few years when I was in high school and a lot of people care a lot about clearance and rules, so if they care about clearance, do they also care about degrees? I also looked more at Senior listings. I put the Senior keyword in there. Here&amp;rsquo;s a government agency position, and they&amp;rsquo;re hiring a Senior DBA. They don&amp;rsquo;t require a degree, but for their SQL Server DBA they want 10 years of experience managing and modifying SQL and Access databases, and they also want 10 years of working with Visual Basic macros. You don&amp;rsquo;t have to have a degree for that but you need to enjoy working with Microsoft Access and Visual Basic macros, which isn&amp;rsquo;t your usual DBA thing. Some job listings are like that.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a government contractor that did say bachelor&amp;rsquo;s degree, they didn&amp;rsquo;t say &amp;ldquo;or equivalent,&amp;rdquo; but they didn&amp;rsquo;t put any special wording on it. Now they do require top-secret or s SBI clearance &amp;ndash; I didn&amp;rsquo;t look up all the acronyms on these jobs &amp;ndash; but they do require the candidate to have some clearance ,and my guess about this job is that if you have the clearance but you don&amp;rsquo;t have the degree, the degree I&amp;rsquo;m guessing is gonna be really negotiable. I know this based on my own experiences, because by the way you know I mentioned I have a really fruity degree in humanities. All of these job listings are saying you know we want somebody with a degree in engineering or computer science, and I still managed to get jobs over the years!&lt;/p&gt;
&lt;p&gt;So I kind of know that when they have this in a listing, they don&amp;rsquo;t always mean it &amp;ndash; and when they do really mean it they often say that in the listing. For example, in the DC area there was a recruiter with a job listing for a Senior DBA. The listing was for a fairly traditional on-call role out there, and they wrote bachelor&amp;rsquo;s degree HIGHLY DESIRED and they put HIGHLY DESIRED in all caps, because a lot of the candidates know that for this type of job, for database administrator jobs, the degree requirement is often very squishy, if it&amp;rsquo;s there at all. And not only do they put HIGHLY DESIRED in all caps, they listed it fifth among the whole list of requirements for the job. They put it pretty high up there.&lt;/p&gt;
&lt;p&gt;This is a case where I actually think whoever&amp;rsquo;s doing this hiring does really care. This is the first listing that we&amp;rsquo;ve gotten to, right? They probably really care about that.&lt;/p&gt;
&lt;p&gt;There was a Senior Database administrator at a university &amp;ndash; this position said a bachelor&amp;rsquo;s and/or master&amp;rsquo;s degree in computer science or related IT field, that was in their requirements. This one actually kind of made me laugh. It didn&amp;rsquo;t make me laugh because of the particular University or anything like that, it made me laugh because recently I was chatting with a university in my area about the potential of me working as an adjunct and possibly &amp;ndash; and this is really loose right, this is not like me getting an actual offer or anything like that &amp;ndash; but potentially teaching a course on Introduction to Databases. The reason that they&amp;rsquo;re interested is because I have a lot of work experience with databases and I have experience teaching. I have hands-on real-world experience and I know how people actually work as DBAs and database developers, not that I have a bachelor&amp;rsquo;s degree or a master&amp;rsquo;s degree in computer science or a related field. So the fact that there&amp;rsquo;s a university who&amp;rsquo;s hiring a Senior database admin and they&amp;rsquo;re like, Oh we&amp;rsquo;d really like you to have a master&amp;rsquo;s degree in computer science, I&amp;rsquo;m like well you may not actually need that to teach it, do you really need it to do the job? But some folks think so.&lt;/p&gt;
&lt;p&gt;Now how hard is this requirement? This one could be squishy — it could be a nice to have for them, it&amp;rsquo;s hard to know.&lt;/p&gt;
&lt;p&gt;Other listings in the DC area: there was a Senior DBA for a government contractor that had BS in computer science or a closely related field. They didn&amp;rsquo;t put it in the main job requirements, they put it in additional job requirements &amp;ndash; and whenever I see it that far down whatever, is in additional I kind of think of as a nice-to-have. They really haven&amp;rsquo;t put it in the main requirements. There&amp;rsquo;s a Senior SQL DBA for a different government contractor, this is another one that they wanted an active secret clearance. They even listed a specific SQL Server certification they wanted someone to have, but they didn&amp;rsquo;t list a degree requirement. So not all government contractors even are listing this as a requirement, and if they do very few of them are really emphasizing it.&lt;/p&gt;
&lt;h2 id="i-finally-looked-at-one-more-area-i-said-how-about-southern-california"&gt;I Finally Looked at One More Area, I Said How About Southern California?&lt;/h2&gt;
&lt;p&gt;I just made the area really big I said look at Southern California.&lt;/p&gt;
&lt;p&gt;Here we found some of my favorite style of job listings. There&amp;rsquo;s AAA of Southern California, who is hiring a Senior DBA &amp;ndash; and this happens sometimes, you&amp;rsquo;ve got folks who&amp;rsquo;ve in the HR department who maybe haven&amp;rsquo;t updated their job listings in a while, so they actually want somebody to have quite a few years of experience with SQL Server, they want a bachelor&amp;rsquo;s degree in computer science or equivalent experience. So we&amp;rsquo;ve got the equivalent experience here, but then they also want proven experience with Query Analyzer and Enterprise Manager. But they do want you to have worked with recent versions of SQL Server. I think someone wrote that job listing about 18 years ago and then it&amp;rsquo;s just been recycled over and over and over again. It doesn&amp;rsquo;t necessarily mean it&amp;rsquo;s a bad job, but it makes me laugh every time I see that. I kinda wanna be like maybe we should update the wording here?&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a health plan in Southern California that does want a bachelor&amp;rsquo;s degree. They even say in business administration, computer science or related field, which I actually thought I was interesting that they broadened that. They want a minimum of eight years of experience in IT consulting, business analysis, or a related field. This is another one of those jobs where I&amp;rsquo;m like: okay I suspect that you care more about the eight years of experience. There is an Oracle application DBAs for a freight tools company that is open to equivalent experience. They do want 10 plus years of overall experience with a minimum of five years working with Oracle apps.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a Senior DBA for an enterprise financial company, and in that case they said quote BS in information systems or relatable field is a required. It &amp;ldquo;is a required.&amp;rdquo; This was a recruiter listing, and recruiter listings are kind of famous for being grammatically questionable, so I&amp;rsquo;m not sure that the hiring manager would like that &amp;ldquo;is a required&amp;rdquo; was used in their listing, but apparently this is another example of &amp;ndash; actually in this case they do really mean it, enough that they&amp;rsquo;re actually saying in there, &amp;ldquo;no this isn&amp;rsquo;t squishy.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="what-i-saw-in-these-listings-matches-up-what-ive-seen-as-being-part-of-the-hiring-process-being-on-the-hiring-end-it-is-really-tricky-to-hire-a-great-database-administrator"&gt;What I Saw in These Listings Matches Up What I&amp;rsquo;ve Seen as Being Part of the Hiring Process, Being on the Hiring End. It Is Really Tricky to Hire a Great Database Administrator.&lt;/h2&gt;
&lt;p&gt;Managers do like college degrees, the people doing the hiring are hanging on to what I see as a kind of old-fashioned way to tell if someone is gonna be a good candidate. I am a person who actually has &amp;ndash; I spent a bunch of time getting my bachelor&amp;rsquo;s degree and then getting a master&amp;rsquo;s degree. I certainly personally see the value in going to college, but I don&amp;rsquo;t think it&amp;rsquo;s the only way to show whether or not you can be a great member of a team and whether you can be effective in a technical environment. Whether you can communicate well. I also think that if managers really are valuing experience &amp;ndash; and when it comes to database administration managers really do value experience, and in part this is because there is no great degree in becoming a DBA.&lt;/p&gt;
&lt;p&gt;Computer Science is not the same thing as database administration. Database administration, maybe there&amp;rsquo;s a couple of classes specifically on that topic, and with database administrators there&amp;rsquo;s a lot of influence on problem solving with very specific technologies and working as part of a team. You don&amp;rsquo;t necessarily get trained on that as part of a computer science degree. So the fact that managers like both these, things they like college degrees and they really like experience means that they go through and they start interviewing different candidates.&lt;/p&gt;
&lt;p&gt;Well, different candidates aren&amp;rsquo;t necessarily going to be a great fit for their team both due to technical skills as well as communication, and how the team works together. So even when you have qualified candidates, it&amp;rsquo;s hard to find the right person. Usually there&amp;rsquo;s something that&amp;rsquo;s got to give, and typically managers will take experience and someone who fits technically with the team, and whose communication skills are good &amp;ndash; typically they&amp;rsquo;ll go ahead and take that person even if they don&amp;rsquo;t have a college degree.&lt;/p&gt;
&lt;p&gt;This was a very non-scientific survey I did of the listings, but the listings that I saw said, &amp;ldquo;We are open to equivalent experience. It would be great if you had a college degree, but we will look at equivalent experience which includes all sorts of life experience and work experience.&amp;rdquo; When people really seem to want a college degree, they actually say so. I saw all of two of those listings in my look through here today. I suspect that even those if you had a college degree and it wasn&amp;rsquo;t in computer science, they would take that as well. I think what they&amp;rsquo;re saying is we would love it if you had a degree in computer science or engineering but we really need you to have a degree because the management at this company won&amp;rsquo;t budge on that one.&lt;/p&gt;
&lt;p&gt;There are some cases where I have found &amp;ndash; and it has been a few &amp;ndash; where management just has this idea that everyone has to have a four-year degree and they won&amp;rsquo;t budge on it.&lt;/p&gt;
&lt;p&gt;In many jobs security clearances or certifications, sometimes they care more about that than they care about a degree.&lt;/p&gt;
&lt;h2 id="so-for-our-questioner"&gt;So for Our Questioner&amp;hellip;&lt;/h2&gt;
&lt;p&gt;The question was: I&amp;rsquo;m on this great career track and I&amp;rsquo;m feeling really good about it, and I&amp;rsquo;m loving it. I&amp;rsquo;m a little worried, is my not having a degree gonna rule out some jobs? Yeah, lacking a degree is gonna rule out some jobs, but in my experience and with what I see in the market, it&amp;rsquo;s gonna be a pretty small amount of jobs.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s more prevalent in some locations than in other locations, like here in the Pacific Northwest I looked around at the job listings and &amp;ldquo;or equivalent experience&amp;rdquo; was everywhere.&lt;/p&gt;
&lt;p&gt;I wouldn&amp;rsquo;t really worry about it, because our questioners in the position where they&amp;rsquo;ve got a mentor, they&amp;rsquo;re building that hands-on experience, and they&amp;rsquo;re making connections with other people. Those connections you make with other people, with people who you work with actively, with people at a local user group that you attend, with people that you meet at conferences &amp;ndash; maybe it&amp;rsquo;s a free SQL Saturday or maybe it&amp;rsquo;s a database conference, those connections are often gonna land you a job! In most of those cases, even if they had been really wanting someone with a college degree, if they&amp;rsquo;ve interacted with you and they know cool things that you&amp;rsquo;ve done, and they&amp;rsquo;ve seen how excited you are about data, and they have a real excitement for you &amp;ndash; even in those cases where they actually really want a degree &amp;ndash; for someone they know, often it&amp;rsquo;s not gonna be a big deal to leap past that on the requirements list.&lt;/p&gt;
&lt;h2 id="i-do-think-theres-a-deeper-question-here"&gt;I Do Think There&amp;rsquo;s a Deeper Question Here&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m looking at all these listings &amp;ndash; I thought it was interesting that there&amp;rsquo;s so much about computer science degrees on these database administrator job listings. I think there is a long term bias in terms of thinking that a college degree is proof that it makes someone smart. And as someone with a master&amp;rsquo;s degree, I can tell you that it&amp;rsquo;s not proof that I&amp;rsquo;m smart at all! But my master&amp;rsquo;s degree isn&amp;rsquo;t in computer science.&lt;/p&gt;
&lt;h2 id="if-i-had-a-computer-science-degree-would-i-be-a-better-dba"&gt;If I Had a Computer Science Degree, Would I Be a Better DBA?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve had some room to think about this recently because my partner in life has gone back to school to study computer science &amp;ndash; Jeremiah Peschka has a degree in English. He had a bachelor&amp;rsquo;s degree in English that he got long ago in a place far away. After he got that bachelor&amp;rsquo;s degree in English, he worked as a developer and he got into database administration. He got into consulting and teaching and worked a lot with data.&lt;/p&gt;
&lt;p&gt;Now he&amp;rsquo;s gone back to school and is working towards getting a PhD in computer science. But with just a bachelor&amp;rsquo;s degree in English, you don&amp;rsquo;t just walk up and say: I would like PhD in computer science please. You need to do the equivalent of &amp;ndash; if you&amp;rsquo;re familiar with medical school, you know that some folks can do a post baccalaureate, what&amp;rsquo;s called a post bac. If they don&amp;rsquo;t have the pre-med courses they can go back and just study up on those courses, then go to med school. There is something similar you can do with computer science, where you don&amp;rsquo;t have to get a whole second bachelor&amp;rsquo;s degree. You can take required undergraduate computer science courses and then after you pass those levels, move into masters and doctorate levels. I&amp;rsquo;ve gotten to watch this. I haven&amp;rsquo;t certainly done all of the work, I haven&amp;rsquo;t done ANY of the work, but I&amp;rsquo;ve watched as he&amp;rsquo;s gone along this journey of doing courses on algorithms, courses on logic, courses on intro to databases, on programming and all this stuff. You certainly learn a lot in a computer science program.&lt;/p&gt;
&lt;p&gt;Does it make you a better database administrator? Well, yes, but I also think that you could get those the same things that you&amp;rsquo;re getting about critical thinking and understanding some of the internals of databases, I think that you can get that from certain work experience.&lt;/p&gt;
&lt;p&gt;We all know that not all job experiences are exciting, and not all job experiences teach us a lot. Some jobs definitely involve more problem-solving, more creativity, more thinking and give us more opportunities to learn than others. I think that from what I&amp;rsquo;ve observed, yeah you can learn a lot from getting that college degree, but the relevant experience that you can get in life and that sometimes you can get just by challenging yourself and outside of your main job, learning things, taking on challenges getting yourself educated, figuring out how you can talk your manager into letting you go to that conference, for example&amp;hellip; That you can build those skills out of there as well. The number of courses that are in a computer science program that are specifically related to database administration, those also are not a lot. I personally I would be interested to hear an argument that says yes DBAs should have computer science degrees, and I would interest be interested to see the argument of why, because at this point in time I personally just don&amp;rsquo;t see the logic to it when it comes to the field of database administration.&lt;/p&gt;
&lt;p&gt;So, I as someone who knows a lot of DBAs who don&amp;rsquo;t have college degrees, as someone who looks at these job listings and sees the &amp;ldquo;or related experience&amp;rdquo; and sees that there&amp;rsquo;s just a few job listings that are saying, no really we really do want a degree &amp;ndash; I wouldn&amp;rsquo;t worry. I still wouldn&amp;rsquo;t worry too much about it.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a long ways from a college degree, I wouldn&amp;rsquo;t freak out about it if you want to be a DBA. It&amp;rsquo;s connecting with other DBAs, building your skills and experience and landing those jobs to build up your experience, especially more and more emerging recent technologies in SQL Server. Those are the things that will continue to serve you in advancing your career and landing jobs as a DBA.&lt;/p&gt;
&lt;p&gt;Thanks so much for joining me!&lt;/p&gt;
&lt;h2 id="now-for-some-comments"&gt;Now, for Some Comments&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Tom says&lt;/strong&gt; &amp;ldquo;or equivalent&amp;rdquo; allows a lot of wiggle room.  If this person is at the halfway mark, they would probably be better served to finish their studies off.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a vote that says, okay if you&amp;rsquo;re at the halfway mark, they would probably be better served to finish. I think halfway is just not very far when it comes to a four-year degree. I know some folks&amp;ndash;it means a lot to them to finish that degree. If you&amp;rsquo;ve got a personal investment and you&amp;rsquo;re gonna love having that degree, then going to school at night can be worth it. I know some folks who&amp;rsquo;ve done that and it&amp;rsquo;s really rewarding for them, and I love that. But if it&amp;rsquo;s not that situation I think you can get a lot of cool jobs without it, but I love hearing your take on it too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ryan says&lt;/strong&gt; if they want Enterprise Manager and Query Analyzer they could be saying that they&amp;rsquo;re still using SQL 2000. That was the kind of interesting thing about the listing is I didn&amp;rsquo;t see that in there. I was reading fast, Ryan, I was reading fast. They did mention a lot of more recent versions, but I would certainly ask them &amp;ndash; like I would I would say any mention of Enterprise Manager or Query Analyzer in a listing is a big old red flag that that makes you want to pull back if you do talk to these folks, kind of pull back things a little bit. Be like, what so what are the older versions of SQL Server that you&amp;rsquo;re running? I need to know, we need to talk about whether this relationship is gonna go further or not! Because it&amp;rsquo;s tricky to manage these old unsupported instances, especially when things go wrong, if they&amp;rsquo;re critical to the business. But yeah, it is one of those one of those fun things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Great question here&lt;/strong&gt;: How can I get fast experience if my current &amp;ndash; and I think I&amp;rsquo;ve got a word missing in here &amp;ndash; if my current job doesn&amp;rsquo;t provide a lot? This is an interesting question and this is I cover this a lot in my junior DBA talks of how do I get a job if I don&amp;rsquo;t have experience. My main takeaways for this, I&amp;rsquo;m gonna do a really high-level summary, are: you always want to be honest. You can build some experience in test environments, but you want to always be honest what you&amp;rsquo;ve learned by testing. You want to make connections with people. Things like going to a local user group, talking to people there. Say hey: I&amp;rsquo;m just starting out and I&amp;rsquo;m building up my experience. How did you get into the DBA jobs here? Do you have any advice for someone just starting out? Do you know anyone who&amp;rsquo;s got junior DBA jobs? Making those connections with people and explaining where you are and asking for their help in your area is going to be your best hope for finding those opportunities.&lt;/p&gt;
&lt;p&gt;Because it is really hard landing those first DBA jobs! It was really hard for me, I had many jobs where I kept just taking jobs where I worked with data and trying to build experience in a production environment managing data flows. Edging more and more towards the more technical things, and then eventually landing it. I didn&amp;rsquo;t know about user groups when I was first starting out and I really wish I&amp;rsquo;d had that to add in &amp;ndash; especially because they&amp;rsquo;re free and they generally meet in evenings. There&amp;rsquo;s also virtual groups as well. A little bit harder to make the in-person connection with those, but you can sometimes do that as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comment from Scott&lt;/strong&gt;: Georgia Tech is offering a masters in computer science for about seven thousand dollars total. I&amp;rsquo;m still working on my BS but it&amp;rsquo;s a thought for anyone wanting to go on. It&amp;rsquo;s all online, Scott says. I think this is really hugely interesting for folks who really are interested in getting master&amp;rsquo;s degree in Computer Sciences, especially when you have a love for the topic. Maybe you want it for getting a job, but you also want to work more on building your knowledge. Obviously I&amp;rsquo;m into that. You don&amp;rsquo;t get a master&amp;rsquo;s degree in philosophy for practical reasons!&lt;/p&gt;
&lt;p&gt;But more and more computer science departments, really good ones are starting to build online programs where you don&amp;rsquo;t have to fly across the country or take two weeks off, or go at night. You can, for reasonable amounts of money, attend University and build degrees online. I am obviously biased towards online education, I don&amp;rsquo;t think there&amp;rsquo;s any secret about that, but I love the fact that more and more this is becoming available. If you don&amp;rsquo;t want to get a degree but you want to audit courses, there&amp;rsquo;s a lot of really great big-name computer science programs that are doing more and more free material online. They don&amp;rsquo;t necessarily land you towards a degree, but they could teach a lot and you could have a lot of fun and learn a lot about yourself in the process. Thanks, that&amp;rsquo;s a great comment. This is why I love doing this online, there&amp;rsquo;s things I didn&amp;rsquo;t think about including that are really important and will be valuable for folks.&lt;/p&gt;
&lt;h2 id="we-have-just-run-out-of-time-and-i-need-to-wrap-this-up-get-this-recorded-and-ship-this-podcast-episode"&gt;We Have Just Run Out of Time, and I Need to Wrap This Up, Get This Recorded and Ship This Podcast Episode!&lt;/h2&gt;
&lt;p&gt;Thank you so much for joining me for Dear SQL DBA. We will be back on May 17th, I&amp;rsquo;ll be talking about dealing with a lack of control as a DBA. It is really interesting as a database administrator how we often get to be responsible for things but we don&amp;rsquo;t get to control everything, and there&amp;rsquo;s interesting things to think about and tips that I&amp;rsquo;ve learned over time about balancing that and making it work that I&amp;rsquo;d like to share.&lt;/p&gt;
&lt;p&gt;If you have thoughts on that - I would love for you to join in. That&amp;rsquo;s gonna be recorded on Thursday, May 17th at 1 p.m. Pacific. Hope to see you then!&lt;/p&gt;</description></item><item><title>Dear SQL DBA: How Do I Prepare for Certification Exams? (video)</title><link>https://kendralittle.com/2018/04/23/dear-sql-dba-how-do-i-prepare-for-certification-exams-video-with-captions-and-transcript/</link><pubDate>Mon, 23 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/23/dear-sql-dba-how-do-i-prepare-for-certification-exams-video-with-captions-and-transcript/</guid><description>&lt;p&gt;In this episode, I talk about how to strategize for and prepare for Microsoft Certification exams, using the Database Fundamentals exam as an example.&lt;/p&gt;
&lt;h2 id="subscribe"&gt;Subscribe&lt;/h2&gt;
&lt;p&gt;If you’d rather listen on the go, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;amp;isi=691797987&amp;amp;ius=googleplaymusic&amp;amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss#&lt;/a&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/gbbRSgKm_xM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h1 id="transcript"&gt;Transcript&lt;/h1&gt;
&lt;p&gt;Welcome to Dear SQL DBA: a podcast and youtube show for SQL Server developers and database administrators.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;h2 id="this-episode-is-all-about-preparing-for-certification-tests"&gt;This Episode Is All About Preparing for Certification Tests&lt;/h2&gt;
&lt;p&gt;I get a lot of questions about certifications&amp;ndash; so many questions that I already have a podcast episode addressing the question: should I get certified? I still think it&amp;rsquo;s worth thinking heavily about whether you want to invest the time and money into getting certifications, and figuring out are these going to be meaningful for your career.&lt;/p&gt;
&lt;p&gt;Certifications has been a really valuable milestone on my path to learning about a lot of topics in SQL Server, but they don&amp;rsquo;t have to be &amp;ndash; and certifications aren&amp;rsquo;t required for you to meet your goals, necessarily, when it comes to your career working with data.&lt;/p&gt;
&lt;p&gt;In this podcast, I&amp;rsquo;m going to talk about how I strategize approaching something like a certification exam, but do you go back and check out that other episode if you&amp;rsquo;re questioning: hey do I need to get certified?&lt;/p&gt;
&lt;p&gt;Because this podcast is all about taking the challenge of certification and making the most of it.&lt;/p&gt;
&lt;h2 id="one-word-of-warning-i-will-be-talking-about-an-example-exam-in-this-in-this-session-but-these-things-change-a-lot"&gt;One Word of Warning: I Will Be Talking About an Example Exam in This in This Session, but These Things Change a Lot!&lt;/h2&gt;
&lt;p&gt;Not only do the exams change, but the certifications themselves change, and the definition of hey what is the certification and what does it cover &amp;ndash; and that is something that shifts over time. So, if you&amp;rsquo;re listening to this episode in the future, don&amp;rsquo;t just assume that this exam is still the same. You want to take this strategy that I&amp;rsquo;m giving you. Take out of it what&amp;rsquo;s meaningful for you and use it as a toolset to approach the exams that you want to take on your own path.&lt;/p&gt;
&lt;p&gt;Now, that being said, the example exam I&amp;rsquo;m talking about that we&amp;rsquo;re gonna say okay, how can we strategize taking this exam for someone who&amp;rsquo;s just getting started on their path towards being a DBA &amp;ndash; that exam is exam 98 364. The database fundamentals exam. Now, this exam covers a lot of ground, and it doesn&amp;rsquo;t assume that the person taking it has all of the job experience&amp;ndash; but it&amp;rsquo;s gonna cover all of the fundamentals, or at least a really wide chunk of them.&lt;/p&gt;
&lt;h2 id="when-were-approaching-an-exam-what-i-like-to-do-is-first"&gt;When We&amp;rsquo;re Approaching an Exam, What I Like to Do Is First&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Get a big-picture view and just really start looking at: what are the skills that this exam is measuring? I want to expand each area and get the details out of the exam description, and then I want to summarize it and analyze it in my own format. I like to use a spreadsheet, and I like to do that because I want to assess myself on the different skills that they&amp;rsquo;re measuring, and also I want to do some analysis on where I may want to prepare and where I may not want to prepare.&lt;/p&gt;
&lt;p&gt;Summarizing the exam is really helpful because these exams can be intimidating. The level of things that they cover. the number of things they cover and the level of detail in them may become overwhelming, and if we don&amp;rsquo;t do that analysis and strategizing about where to invest our time, we may quickly become overwhelmed&amp;ndash; and we may become, you know, kind of frightened of the exam. That doesn&amp;rsquo;t put us in the best place to take the exam.&lt;/p&gt;
&lt;h2 id="we-want-to-set-ourselves-up-so-that-we-have-good-confidence-going-into-it-and-feel-that-we-have-a-good-chance-to-tackle-the-exam"&gt;We Want to Set Ourselves Up So That We Have Good Confidence Going into It and Feel That We Have a Good Chance to Tackle the Exam&lt;/h2&gt;
&lt;p&gt;Looking at the database fundamentals exam, it has multiple areas, and it lists out for each of these areas how much weight is put on that area in the exam.&lt;/p&gt;
&lt;h2 id="the-first-area-that-is-covered-for-database-fundamentals-is-this-concepts-section"&gt;The First Area That Is Covered for Database Fundamentals Is This Concepts Section&lt;/h2&gt;
&lt;p&gt;Understanding core database concepts is estimated to be 20 to 25 percent of the weight of the exam.&lt;/p&gt;
&lt;p&gt;We get a fair amount of detail about what they&amp;rsquo;re going to ask us about: it says you need to understand how data is stored in tables, you need to understand relational database concepts as well as data manipulation language and data definition language. All of these things together are up to 1/4 of the weight of the exam. All right, so I take out these headings and I put those into my spreadsheet.&lt;/p&gt;
&lt;p&gt;I may read some of the detail on here to make sure that I understand what this means as well.&lt;/p&gt;
&lt;h2 id="the-next-section-of-the-exam-is-creating-database-objects"&gt;The Next Section of the Exam Is Creating Database Objects&amp;hellip;&lt;/h2&gt;
&lt;p&gt;&amp;hellip;and this is again 20 to 25% of the weight of the exam. This section, creating database objects, contains questions on choosing data types, understanding tables and how to create them, creating views and creating stored procedures and functions. Now, there&amp;rsquo;s parts of these that may sound familiar if we think back to the first section. The first section had understanding how data is stored in tables, which is understanding columns and rows. The second section of this says understanding tables and how to create them. It&amp;rsquo;s very very similar to the first one. It&amp;rsquo;s more about understanding T- SQL to create a table, but of course to understand the T-SQL to create a table, we need to understand these concepts of columns and rows.&lt;/p&gt;
&lt;p&gt;So there is some overlap of concepts in here. If I understand tables and how to create them I am going to understand most likely how data is stored in tables, as long as I understand not just how to&amp;ndash; you know create tables, but the fact that they can have rows in them as well.&lt;/p&gt;
&lt;h2 id="these-sections-of-this-exam-arent-measuring-totally-separate-things"&gt;These Sections of This Exam Aren&amp;rsquo;t Measuring Totally Separate Things&amp;hellip;&lt;/h2&gt;
&lt;p&gt;..and if I understand some concepts well it may cover more than one skill measured in the exam. The first section of the exam is about manipulating data: it&amp;rsquo;s about selecting data inserting data, updating data, and deleting data. And again, some of these may sound similar because that first section that was big picture already covered a lot of these concepts. To understand selecting data we need to understand relations between tables. To understand inserting updating and deleting data, these are all ways that we can manipulate data.&lt;/p&gt;
&lt;h2 id="the-next-section-of-the-exam-is-called-understanding-data-storage"&gt;The Next Section of the Exam Is Called Understanding Data Storage&amp;hellip;&lt;/h2&gt;
&lt;p&gt;&amp;hellip;and this is an example I think of where some of the titles may not mean what I think they mean at first. Understanding data storage&amp;ndash; if I only saw those words I might think that this was about how to create files in the file system and how SQL Server pages store data, or how data access to storage is done. But when I look into the subheadings of this topic it says that understanding data storage consists of normalization, primary, foreign and composite keys, and indexes. So they&amp;rsquo;re talking more about what are the ways in which we design our data structures in the SQL Server. It&amp;rsquo;s not talking about the Windows file system and how SQL Server talks to the Windows file system necessarily, and that&amp;rsquo;s part of why I think it&amp;rsquo;s useful to go in and expand these and pull out the sub headings: because if I simply read the big picture categories the way in which I interpret those words may not be really what they&amp;rsquo;re talking about. This data storage portion is 15% to 20% of the exam.&lt;/p&gt;
&lt;h2 id="now-theres-one-last-section-on-this-exam-called-administering-a-database"&gt;Now, There&amp;rsquo;s One Last Section on This Exam Called Administering a Database&lt;/h2&gt;
&lt;p&gt;Administering a database is only 10 to 15%, and they only list two concepts or two skills inside administering a database. There&amp;rsquo;s there&amp;rsquo;s definitely more to administering a database than this, but in the fundamentals category. the skills they&amp;rsquo;re talking about are database security concepts and backups and restores. This is a great example of an area where if you tried to master all parts of administering a database to pass the database fundamentals exam, you would be doing way more work than this exam covers. And that might be really really valuable, but we&amp;rsquo;re really at a big picture level here, and at the fundamentals level they&amp;rsquo;re really doing some selection of topics and deciding exactly what is fundamental to database administration.&lt;/p&gt;
&lt;h2 id="all-of-these-headings-that-ive-listed-at-all-of-these-skills-i-take-these-skills-and-put-them-into-a-spreadsheet-that-gives-me-a-nice-big-picture-view"&gt;All of These Headings That I&amp;rsquo;ve Listed at All of These Skills, I Take These Skills and Put Them into a Spreadsheet That Gives Me a Nice Big Picture View&lt;/h2&gt;
&lt;p&gt;Each of these skills is approximately five and a half percent to seven percent of the exam, and as we said there is overlap in some of these skills that were listed. So data manipulation language is 5.6 percent just as an overview topic but then inserts updates and deletes are each seven percent as well. So if I want to work on just a lot of T SQL and understanding how to select and manipulate data, that alone is gonna have quite a lot of coverage on this exam.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth assessing that, because just looking at individual skills you may underestimate the weight that something has on the exam, so look for redundancy in the areas listed.&lt;/p&gt;
&lt;h2 id="i-also-like-to-add-some-columns-to-this-spreadsheet-and-for-each-skill-thats-being-measured-assess-what-is-my-confidence-level-in-this-area"&gt;I Also Like to Add Some Columns to This Spreadsheet and for Each Skill That&amp;rsquo;s Being Measured, Assess: What Is My Confidence Level in This Area?&lt;/h2&gt;
&lt;p&gt;You do need to know yourself a little bit&lt;/p&gt;
&lt;p&gt;Do you tend to be overconfident?&lt;/p&gt;
&lt;p&gt;Do you tend to be really self-critical?&lt;/p&gt;
&lt;p&gt;Try to not be so self-critical or dial it back a little bit. If you tend to be overconfident you want to have a fair idea of this just for your own purposes. What we&amp;rsquo;re really saying is where are my areas where I&amp;rsquo;m strongest? Where my areas where I&amp;rsquo;m weakest? This will help&amp;ndash; this will be part of the formula to figure out where I want to study&amp;ndash; but not the whole formula because I also want to look at these areas and note separately: how interested am I in this area? So for example, for this exam what I did is I went way back and I thought about Kendra before she was even a Junior DBA. Kendra when she was just starting out. I really loved writing queries&amp;ndash; that was one of the first things I did with SQL Server was figure out how to interpret data in the database and make it useful. Looking through these areas I had medium confidence on storing data in tables, and medium confidence about relational database concepts, because I was used to working with tables and joining them. I was a little bit used to data manipulation language because I would use temp tables, but I wasn&amp;rsquo;t super confident. I had low confidence when it came to data definition language, because I would do a lot of things like select into a temp table and then manipulate the data in there.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t feel that I knew a lot about data types, and honestly looking back, I would have underestimated myself a lot, I would have said low comfort. but actually I DID know a lot of them, I just didn&amp;rsquo;t have a lot of knowledge of what I didn&amp;rsquo;t know in that area, right? Because I only knew&amp;ndash; oh I&amp;rsquo;ve interacted with these data types. It turns out I&amp;rsquo;d interacted with a lot more data types than I really gave myself credit for. But I would go through each of these areas and rank: high confidence, medium confidence, low confidence&amp;ndash; or if I just literally didn&amp;rsquo;t know anything about it, just put question marks. I knew absolutely nothing about indexes, I knew I didn&amp;rsquo;t know what an index was at this point in my career, so I would have just put like question mark question mark question mark there. I also knew hardly anything about security. All I knew about security was how to ask to get access to something. I wasn&amp;rsquo;t at the point where I was a database administrator so I had really low or non-existent knowledge in some areas in these exams, but also there were some areas that were interesting to me&amp;ndash; where I had really high interest. And then there were other areas where I had really low interest. Noting those is really really important as well.&lt;/p&gt;
&lt;h2 id="saying-that-something-is-low-interest-isnt-saying-that-its-not-important-or-it-is-not-valuable"&gt;Saying That Something Is Low Interest, Isn&amp;rsquo;t Saying That It&amp;rsquo;s Not Important or It Is Not Valuable&lt;/h2&gt;
&lt;p&gt;It really is a question of what is something that I just I have a desire to learn more about. I find it really compelling, or something that I think might be really useful to me in the short term.&lt;/p&gt;
&lt;p&gt;At that point in my career, where I was really focusing on getting a lot better using databases, as somebody who used T- SQL, the areas that were of the greatest interest for me had to do with becoming more and more of an expert at creating objects in the database, and I just really wasn&amp;rsquo;t the point where I was ready to learn about backup and restore. It was later in my career that that became much higher interest to me. You want to avoid the anti-pattern of being the perfectionist at this point. There can be, for many of us, a tendency to say: I&amp;rsquo;m just not ready to take the exam yet and to get stuck in this place where we never get started, because we&amp;rsquo;re like oh I haven&amp;rsquo;t learned these three things yet. To me certifications can help move your knowledge forward, and a big part of that is just getting to the point where you&amp;rsquo;re ready and excited to try the exam.&lt;/p&gt;
&lt;h2 id="to-me-the-point-of-being-ready-and-excited-to-try-the-exam-is-when-i-feel-that-i-have-enough-coverage-of-these-areas-and-im-in-the-right-mental-state"&gt;To Me, the Point of Being Ready and Excited to Try the Exam Is When I Feel That I Have Enough Coverage of These Areas, and I&amp;rsquo;m in the Right Mental State.&lt;/h2&gt;
&lt;p&gt;But that right mental state isn&amp;rsquo;t that I&amp;rsquo;m confident I know everything.&lt;/p&gt;
&lt;p&gt;That right mental state is: I see the challenge in the questions and I think I can get past the tough videogame level of this certification exam. There&amp;rsquo;s gonna be moments when I&amp;rsquo;m like squinting at the certification screen and I&amp;rsquo;m trying to get past something, but I want to be having fun while I do it, because honestly for me I am better at exams when I&amp;rsquo;m in that mood of: okay I think I&amp;rsquo;ve got what it takes to pass this exam, and I&amp;rsquo;m gonna go for it, and I&amp;rsquo;m really going for it. I&amp;rsquo;m not like at this oh I know everything overconfidence stage.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m at the: I think I can tackle it competitive stage. Not competitive with other people, but really competitive almost against a video game boss type thing in the exam. I&amp;rsquo;m competing against the challenge that&amp;rsquo;s been set up for me. Looking at how I&amp;rsquo;ve scored myself in my imaginary report writing Kendra, approaching the fundamentals exam, if I highlight areas where I ranked myself as either medium or high comfort level, looking at the percentage is given to each skill on the exam comes out to about 42% coverage of the exam. Honestly, that&amp;rsquo;s not so bad! That&amp;rsquo;s a pretty confident little Report Writer Kendra, who&amp;rsquo;s like oh you know I know something about these other areas, even areas where I have kind of low confidence, I&amp;rsquo;m gonna be able to possibly make some guesses in those. But I think I&amp;rsquo;m gonna be able to make a really good guess if I have medium or high confidence in that area.&lt;/p&gt;
&lt;h2 id="42-coverage-isnt-bad-but-i-might-want-to-bring-that-up-a-little-bit"&gt;42% Coverage Isn&amp;rsquo;t Bad, but I Might Want to Bring That Up a Little Bit&lt;/h2&gt;
&lt;p&gt;I might want to get to the point where I have medium confidence in some other areas on this exam, but I&amp;rsquo;m not gonna try to cover every single area on the exam, because I just want to get to that competitive fun-loving part. I need to pick out other skills that I want to level up, and here is where that interest ranking comes in. Areas where I have low confidence, but I have high interest: these are things that are actually going to be valuable to me to learn at this point in my career, because I have either an excitement about them, or I think they may be useful to me, but I&amp;rsquo;m not very confident about me. Those areas are the ones where I want to go into those and say: yeah okay I&amp;rsquo;m not super confident about creating tables with T-SQL, I want to build that up because I have high interest.&lt;/p&gt;
&lt;p&gt;Same thing with creating views and creating procedures and functions. I&amp;rsquo;m excited about learning those and preparing for this exam has brought to light: hey here&amp;rsquo;s something I&amp;rsquo;m excited about that I don&amp;rsquo;t have medium confidence in. That is an exciting thing to go out and learn to me! So I want to avoid those areas where I have low confidence, but my interest is also low. Those, hey maybe later on my interest is going to be higher in those, but I&amp;rsquo;m not gonna pick those out to tackle right now for this exam. If little Report Writer Kendra tackles those areas where she has lower confidence and higher interest, and she if she gets those up to medium or high level interest, then I&amp;rsquo;m gonna have 67% coverage of topics on this exam. And at that point I&amp;rsquo;m gonna say: okay I&amp;rsquo;m gonna go ahead and give this a try and see how I do, because I have a good level of coverage, and confidence enough that I feel good enough about to try and tackle this thing!&lt;/p&gt;
&lt;h2 id="my-study-style-for-these-areas-where-i-have-low-confidence-and-high-interest-my-particular-study-style-is-very-hands-on"&gt;My Study Style for These Areas Where I Have Low Confidence and High Interest, My Particular Study Style Is Very Hands-On.&lt;/h2&gt;
&lt;p&gt;This is just how I learn. I have always learned something better if I go out and research it, and write down notes. I have to do something&amp;ndash; I have to either write down notes, or I have to write a demo script. Learning for me is the best when I have a problem. Maybe it&amp;rsquo;s is me creating the problem, or maybe it&amp;rsquo;s just me saying okay I want to learn how to create functions, so I&amp;rsquo;m going to look at some examples of functions online and then I&amp;rsquo;m gonna use a demo database and come up with my own function, and then make sure I know how to use it. My tools for preparing for these are things like sample databases, evaluation&amp;ndash; or Developer Edition, rather, of SQL Server, which is now free. Evaluation edition is free - but it expires, so Developer Edition is awesome.&lt;/p&gt;
&lt;p&gt;Books Online and online documentation and search engines and blogs&amp;ndash; but actually not just reading for me, really getting my hands on things helps me learn. Adapt that to your own style of learning, of course. If saying something out loud helps you learn, then you want to say things out loud. I really really&amp;ndash; when I&amp;rsquo;m preparing for these exams&amp;ndash; like to get myself into the mindset of approaching a game. Maybe it&amp;rsquo;s a video game, maybe it&amp;rsquo;s some sort of competition for you, but for me when I&amp;rsquo;m approaching these questions with exams I want to learn to read the question critically.&lt;/p&gt;
&lt;p&gt;And this is something that sometimes folks like to do practice exams for.&lt;/p&gt;
&lt;h2 id="i-dont-think-that-the-practice-exams-all-have-to-be-official-practice-exams"&gt;I Don&amp;rsquo;t Think That the Practice Exams All Have to Be Official Practice Exams&lt;/h2&gt;
&lt;p&gt;For example, on SQLWorkbooks, I have a bunch of free quizzes&amp;ndash; and I am NOT claiming that these free quizzes are anything like certification quizzes. But they are free, and they do give you a chance to read the questions critically, to practice eliminating answers where you&amp;rsquo;re like: okay I know that one&amp;rsquo;s not it, and I know that one&amp;rsquo;s not it, so I&amp;rsquo;m down to two, and now I&amp;rsquo;m gonna &amp;ndash;how I can decide between these two? You also can help get into the habit of saying: I&amp;rsquo;m going to look at&amp;ndash; gonna run through all the questions on this quiz, and I&amp;rsquo;m gonna kind of set myself, that I&amp;rsquo;m gonna keep timing in mind while I do it. So, if one question is really tricky, I&amp;rsquo;m gonna table it and I&amp;rsquo;m gonna come back to it later.&lt;/p&gt;
&lt;p&gt;Now, my quizzes don&amp;rsquo;t have the functionality&amp;ndash; I don&amp;rsquo;t have hundred question quizzes, so I don&amp;rsquo;t have the functionality of marking a question for review&amp;ndash; but in many of these online exam situations you do have that ability&amp;ndash; which being mindful of the time and not getting stuck on a question is a really important skill. And that&amp;rsquo;s something that any practice quiz can help you with if you get used to: okay I&amp;rsquo;m gonna go past this question and I&amp;rsquo;m not gonna let it get to me, I can come back to it at the end. Just that practice of being comfortable with that and having it not ruffle you too much can be very very useful.&lt;/p&gt;
&lt;p&gt;Timing is a huge part of being quite being successful, not only in video games, but also at quizzes.&lt;/p&gt;
&lt;h2 id="calmness-and-preparing-for-the-test-ahead-of-time-can-also-help-you-out-a-ton"&gt;Calmness and Preparing for the Test Ahead of Time Can Also Help You Out a Ton&lt;/h2&gt;
&lt;p&gt;I have learned the hard way that anytime I&amp;rsquo;ve got something that is sort of an important thing that I want to do well coming up: it might be an exam, it might be an important meeting, it might be a long flight, it might be any critical situation: I want to do my best at that, I may want to start thinking about preparing for it a week in advance, or sometimes even more. Doing things like saying: I&amp;rsquo;m going to start getting to bed at a consistent time so that the night before the exam I have this evening ritual where I wind down where I go to sleep, where I&amp;rsquo;m not staying up all night. Because for me, just getting and having a routine going into the exam where I&amp;rsquo;m calm, where I&amp;rsquo;ve been doing healthy things like walking my dog and working out, it puts me into just a much better place to take the exam. A much more confident place and a more relaxed place. I am also personally into meditation.&lt;/p&gt;
&lt;h2 id="meditating-the-morning-before-a-big-event-makes-a-huge-difference-for-me"&gt;Meditating the Morning Before a Big Event Makes a Huge Difference for Me.&lt;/h2&gt;
&lt;p&gt;It helps me remember to breathe during the exam, it makes it easier to not get stuck on things like tough questions, to not have them bug me and get into my head. Because a lot of the folks who have problems with exams &amp;ndash; times when I&amp;rsquo;ve had problems with the exams have been times when I&amp;rsquo;ve gotten into a place of fear, where I&amp;rsquo;ve gotten really nervous, and I&amp;rsquo;m like oh oh I didn&amp;rsquo;t do well on that question! Having a question haunt you during an exam, or a series of questions haunt you can really be tough. But if you have that mindset of saying: all right, I got knocked out of that question, maybe, I&amp;rsquo;m not sure if I got it right, but okay I&amp;rsquo;m gonna tackle this next one! And now my mind is fresh, my mind is clear, I&amp;rsquo;m ready to get this. I&amp;rsquo;ve got my shoulders down and deep breath &amp;ndash; self-critical thoughts have gone past me.&lt;/p&gt;
&lt;p&gt;That is the place where you&amp;rsquo;re more likely to rock that exam. Building up these habits of getting to a clear mental space&amp;ndash; and having had a full night&amp;rsquo;s sleep really can help you rock out that exam and stay in that mindset of: hey I am going to take this exam down, and get past this confidently. Knowing that the exam doesn&amp;rsquo;t mean anything about you is really really helpful when it comes to having a great time during the exam, to me.&lt;/p&gt;
&lt;h2 id="the-perfect-exam-taking-if-i-got-to-you-know-level-100-of-exam-taking-i-would-be-in-a-place-where-i-could-take-an-exam-that-i-did-terrible-at-and-still-have-a-good-time-and-still-learn-something-from-the-experience"&gt;The Perfect Exam Taking&amp;ndash; if I Got to You Know Level 100 of Exam Taking, I Would Be in a Place Where I Could Take an Exam That I Did Terrible At, and Still Have a Good Time, and Still Learn Something from the Experience&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d be able to say, after this, okay, maybe that was a disaster, but what did I learn from the questions it asked me? I&amp;rsquo;m gonna learn some things about the subject matter itself just from analyzing the questions they asked me. And what did I learn about what I want to do? Maybe I&amp;rsquo;ve discovered that despite my research, this exam is actually not related to what I want to do, and that, whoops I maybe I don&amp;rsquo;t want to pursue this!&lt;/p&gt;
&lt;p&gt;But maybe what I&amp;rsquo;ve learned is, okay, I&amp;rsquo;m gonna get my results back and it was it was Cathrine Wilhelmsen who pointed out&amp;ndash; she said hey you know, you get back the skill results, an analysis of where you were strongest and where you were weakest. If this is something you want to pursue, you can use that to redesign the areas you want to study in. You can take that list and you can rank it: high interest, medium interest, low interest. It has just ranked you on your confidence levels, or rather your your skill levels, right? So you can take that and use it as your map to your study plan. But really, the sign of a great exam is learning as much as you can from that exam, and using it to move forward. At the end of the exam, you want to be in place where you don&amp;rsquo;t use the exam to judge yourself. I know it&amp;rsquo;s something&amp;ndash; I know it&amp;rsquo;s hard to say this exam means nothing about ME. Look at the exam results as meaning something about what to DO next.&lt;/p&gt;
&lt;p&gt;If you pass the exam, maybe you want to take another exam next. Maybe you don&amp;rsquo;t. But if you don&amp;rsquo;t pass the exam&amp;ndash; same thing. Maybe you want to use that to redefine your study areas, maybe you don&amp;rsquo;t. It&amp;rsquo;s all up to you and it really is completely about choosing your own adventure.&lt;/p&gt;
&lt;h2 id="please-please-please-dont-take-negative-exam-results-to-mean-that-you-are-not-good-enough"&gt;Please Please Please Don&amp;rsquo;t Take Negative Exam Results to Mean That You Are Not Good Enough&lt;/h2&gt;
&lt;p&gt;There are a lot of super smart people out there, just tons of super smart people who haven&amp;rsquo;t passed these exams the first time. Maybe they haven&amp;rsquo;t passed these exams ever.&lt;/p&gt;
&lt;p&gt;These exams are a challenge, and they can be part of your journey to your career. They do not have to be.&lt;/p&gt;
&lt;p&gt;And they do not have to define you. They&amp;rsquo;re an achievement you can have, but they aren&amp;rsquo;t something that judges you, and they aren&amp;rsquo;t something that says what you are worth.&lt;/p&gt;
&lt;p&gt;You are worth a lot regardless of whether you&amp;rsquo;ll ever take a certification exam.&lt;/p&gt;
&lt;h2 id="now-getting-more-for-your-buck"&gt;Now, Getting More for Your Buck&lt;/h2&gt;
&lt;p&gt;There is definitely a path&amp;ndash; like if you are saying okay these exams are expensive, and I want to do them, but I want to make sure that I get the absolute most out of the certification experience&amp;ndash; I believe that the way to do that is when you are studying for the exam, when you find those areas where you say, okay, I I have low confidence but I have high interest: start a blog and write about those things as you learn them. That will not only help you learn them and keep you on track, but if you&amp;rsquo;re consistent, building that blog that blog is going to be the thing that helps you get a job moreso than the certifications ever will. Because just the fact that you&amp;rsquo;ve passed a certification or a set of exams for a certification, that tells your employer may be that you&amp;rsquo;re persistent&amp;ndash; but sort of at a high level. A distant level, right? They don&amp;rsquo;t know a ton about that.&lt;/p&gt;
&lt;p&gt;But if you blog about those areas while you&amp;rsquo;re learning about them, and you do it consistently, that tells your employer: hey how do they approach problem-solving, and in great detail! They can see in sampling your blog posts how you&amp;rsquo;re analyzing something, why you think something is interesting, what your writing skills are&amp;ndash; and a little bit about your personality.&lt;/p&gt;
&lt;h2 id="that-blog-can-absolutely-boost-your-career-in-a-way-that-the-certification-by-itself-does-not"&gt;That Blog Can Absolutely Boost Your Career in a Way That the Certification by Itself Does Not&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a little bit like getting to watch somebody practice for the Olympics rather than just hearing how they ranked in different events. Seeing how someone is working out and how they&amp;rsquo;re attaining and sharing knowledge tells you a ton about that person, and that can absolutely be a worthwhile thing to list on your resume and to share with potential employers, as well as your colleagues in the community&amp;ndash; it&amp;rsquo;s about you and about your interests in SQL Server.&lt;/p&gt;
&lt;h2 id="thank-you-so-much-for-joining-me-for-this-episode-of-dear-sql-dba"&gt;Thank You So Much for Joining Me for This Episode of Dear SQL DBA.&lt;/h2&gt;
&lt;p&gt;I have some upcoming live episodes that I&amp;rsquo;ll be recording: on May 2nd I&amp;rsquo;ll be talking about the question, &amp;ldquo;Do DBAs need college degrees?&amp;rdquo; Then following that we&amp;rsquo;ll be talking about dealing with lack of control as a DBA, we&amp;rsquo;ll talk about being a woman in technology on the internet, and training resources for SQL Noobs is coming up on June 13th. That one&amp;rsquo;s gonna be a ton of fun.&lt;/p&gt;
&lt;p&gt;Thanks so much folks! See you in a podcast episode soon.&lt;/p&gt;</description></item><item><title>Query Store Cleanup Can be Part of a Blocking Chain</title><link>https://kendralittle.com/2018/04/18/query-store-cleanup-can-be-part-of-a-blocking-chain/</link><pubDate>Wed, 18 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/18/query-store-cleanup-can-be-part-of-a-blocking-chain/</guid><description>&lt;p&gt;Forgetfulness can lead to learning something new. This is a bit of a nightmare when it happens in production, but a treat when it happens in an isolated test system&amp;ndash; and that&amp;rsquo;s how I learned this.&lt;/p&gt;
&lt;p&gt;I left a bit of blocking open on my test VM, and forgot about it.&lt;/p&gt;
&lt;p&gt;I was using the &lt;a href="https://github.com/LitKnd/BabbyNames/releases/tag/v1.1"&gt;BabbyNames sample database&lt;/a&gt;. In one session, I had run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRANSACTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I left this session sleeping, its open transaction holding a schema modification lock against the ref.FirstName table.&lt;/p&gt;
&lt;p&gt;In another session, I ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I did my testing with this setup, then went back to editing video, and forgot about it.&lt;/p&gt;
&lt;p&gt;I forgot to unblock it.&lt;/p&gt;
&lt;h2 id="later-i-came-back-and-wanted-to-measure-something-in-query-store"&gt;Later, I Came Back and Wanted to Measure Something in Query Store&lt;/h2&gt;
&lt;p&gt;This is an isolated test system, so I went to clean out Query Store as a reset. I didn&amp;rsquo;t need any of the old information in there, so I ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_STORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I was surprised when I didn&amp;rsquo;t see this complete very quickly, as it normally does.&lt;/p&gt;
&lt;h2 id="i-checked-for-blocking-in-sp_whoisactive-and-found-that-my-cleanup-was-blocked"&gt;I Checked for Blocking in sp_WhoIsActive, and Found That My Cleanup Was Blocked&lt;/h2&gt;
&lt;p&gt;I used Adam Machanic&amp;rsquo;s free &lt;a href="http://whoisactive.com"&gt;sp_WhoIsActive procedure&lt;/a&gt; to check what was going on. Here is the blocking chain:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/blocking-chain.png"&gt;
&lt;/figure&gt;
&lt;h2 id="clearing-query-store-created-two-sessions"&gt;Clearing Query Store Created Two Sessions&lt;/h2&gt;
&lt;p&gt;Session 40 shows no sql_text, but it appears when I run the QUERY_STORE CLEAN all command, and disappears when I cancel it. It also shows not &amp;ldquo;sql_command&amp;rdquo; if I run sp_WhoIsActive with @get_outer_command=1, and it shows no lock information if I use @get_locks=1.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s clearly getting locks, because it&amp;rsquo;s blocking its little friend, session 74, but it&amp;rsquo;s just not showing what it&amp;rsquo;s doing.&lt;/p&gt;
&lt;h2 id="meanwhile-session-74-is-waiting-on-a-lock-on-syssysschobjs"&gt;Meanwhile, Session 74 Is Waiting on a Lock on sys.sysschobjs&lt;/h2&gt;
&lt;p&gt;Although we can&amp;rsquo;t see the locks directly on session 40, I can see that session 74 (who is blocked by session 40, who is in turn locked by the alter table) is waiting for a shared key lock on the cost index on the sys.sysschobjs system table.&lt;/p&gt;
&lt;p&gt;Sys.sysschobjs is &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-tables/system-base-tables"&gt;documented&lt;/a&gt;, it &amp;ldquo;Exists in every database. Each row represents an object in the database.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If I connect to the Dedicated Admin connection, I can query the sys.syssschobjs table - and I can read it if I allow dirty reads (seeing the uncommitted data):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sysschobjs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sso&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FirstName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is a modified date on this table (column name modified), which was updated around when I started the modification on the table.&lt;/p&gt;
&lt;h2 id="i-dont-think-this-is-a-bad-thing---im-writing-this-post-just-to-document-it"&gt;I Don&amp;rsquo;t Think This Is a Bad Thing - I&amp;rsquo;m Writing This Post Just to Document It&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/come-back-later.jpg" width="230"&gt;
&lt;/figure&gt;
One cool thing in Query Store is that it has some knowledge of the objects in a database. It will tell you if a query is part of a procedure, for example.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a good thing, but it is probably one of the reasons that Query Store reads from the same system tables that may be locked if we modify the schema of objects.&lt;/p&gt;
&lt;p&gt;Hopefully, most folks don&amp;rsquo;t:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have long running transactions that modify objects in production&lt;/li&gt;
&lt;li&gt;Clear out Query Store data often in production (it&amp;rsquo;s useful information, and the basis for some cool features)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are unfortunate enough to have BOTH of these patterns, you may run into blocking.&lt;/p&gt;
&lt;p&gt;This could also occur if you are trying to clear out Query Store when an offline index rebuild is running.&lt;/p&gt;</description></item><item><title>Dear SQL DBA Q&amp;A: A Poorly Indexed ISV Database</title><link>https://kendralittle.com/2018/04/16/dear-sql-dba-qa-a-poorly-indexed-isv-database/</link><pubDate>Mon, 16 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/16/dear-sql-dba-qa-a-poorly-indexed-isv-database/</guid><description>&lt;p&gt;At a recent conference, two speakers reminded me of something important: when you put effort into learning something or helping folks, don&amp;rsquo;t simply put your words in private emails or post-it notes on your desk. Whenever possible, blog it as well. It can help other people, and it can also help &lt;em&gt;you&lt;/em&gt; remember it in the future!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been kinda/sorta/pretty good about this when it comes to Dear SQL DBA questions. I am going to start being more consistent about it, and sharing the answers with YOU GUYS, too.&lt;/p&gt;
&lt;p&gt;Know that you are always invited to also be the SQL DBA on the other end of the email, too, and chime in with your take in the comments. Feel free to disagree with me, but be kind and respectful to the anonymous questioner&amp;ndash; there&amp;rsquo;s a person on the other end of that keyboard.&lt;/p&gt;
&lt;h2 id="question-ive-got-a-poorly-indexed-database-from-a-commercial-software-vendor-what-should-i-do"&gt;Question: I&amp;rsquo;ve got a poorly indexed database from a commercial software vendor. What should I do?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve encountered a performance issue which I believe is related to indexing. Our database (created by a commercial software vendor) includes a table with over 78 million rows&amp;hellip; and no clustered index! This table is queried by the software many times daily and the effects appear to be hindering our performance.&lt;/p&gt;
&lt;p&gt;There are two non-clustered indices on the offending table: one non-unique including a column called [ColumnA], and the other is unique and includes only [ColumnB] which is the primary key. Both [ColumnA] and [ColumnB] are of uniqueidentifier data type, so I believe that adding a clustered index would hinder performance (please correct me if I&amp;rsquo;m wrong!).&lt;/p&gt;
&lt;p&gt;The problem is that the query which hits this table requests four columns in addition to [ColumnA] and [ColumnB] which are not included in the indices. The estimated query plan shows a RID Lookup (99% estimated cost!) on this table and I really want to get rid of it so we can boost performance, but I&amp;rsquo;m really hesitant to make any changes to the indices on a table of this size.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, I know some of you out there have immediately started itching. We&amp;rsquo;ve got a heap with 78 million rows (not sure how many GB it is, but that&amp;rsquo;s a few rows), we&amp;rsquo;ve got a couple of GUID columns, and we have got what sounds to be a dramatically bad indexing solution.&lt;/p&gt;
&lt;p&gt;I do immediately have doubts about whether this table should be a heap or not &amp;ndash; and I also immediately wonder if deletes happen against this heap, and if it might have a lot of empty space trapped in the heap from deletes that haven&amp;rsquo;t escalated, or forwarded records &amp;ndash; issues specific to heaps.&lt;/p&gt;
&lt;p&gt;Depending on how the table is most often queried, a clustered index might make everything faster.&lt;/p&gt;
&lt;h2 id="but-not-so-fast-kendra"&gt;But Not So Fast, Kendra&lt;/h2&gt;
&lt;p&gt;Since this database is created by a commercial vendor, there&amp;rsquo;s more to think about. We can&amp;rsquo;t just spring into action.&lt;/p&gt;
&lt;p&gt;I wrote a little bit about these types of databases here: &lt;a href="https://kendralittle.com/2017/01/10/administering-cots-databases-isvs-third-party-vendors/"&gt;/2017/01/10/administering-cots-databases-isvs-third-party-vendors/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first thing I would identify is around item #2 in that article: what is the situation with the vendor, what is the support agreement, and how do you work with it? If you go changing around things without first figuring out what that situation is, you might improve performance in the short term, but end up facing a big old problem the next time an upgrade comes out for the software, or end up unsupported if something goes wrong.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a bummer that you can&amp;rsquo;t just get right to tuning, but I&amp;rsquo;ve known folks to get really burned by it before.&lt;/p&gt;
&lt;p&gt;I have also known cases where folks who explained the problem to the vendor were happily surprised that the vendor had a fix for that situation. (Maybe they have an alternate set of indexes they give to clients at a certain scale, or other changes.)&lt;/p&gt;
&lt;p&gt;So it&amp;rsquo;s worth investigating first with the vendor. Depending on how things turn out there, I would be interested in looking at a test environment for the indexing question, and personally I would test out a clustered index on one of those unique keys.&lt;/p&gt;</description></item><item><title>A Case of Inconsistent Wait Stats and Query Duration</title><link>https://kendralittle.com/2018/04/11/a-case-of-inconsistent-wait-stats-and-query-duration/</link><pubDate>Wed, 11 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/11/a-case-of-inconsistent-wait-stats-and-query-duration/</guid><description>&lt;p&gt;You know how they say &amp;ldquo;don&amp;rsquo;t sweat the small stuff&amp;rdquo;?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s good advice for lots of things, but when it comes to query tuning - I WANT TO KNOW MORE when something is inconsistent. I just can&amp;rsquo;t let it go. I go total X-Files: The Truth Is Out There.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Candy-different.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;The bright side of this habit is that it makes finding blog topics fairly easy.&lt;/p&gt;
&lt;h2 id="i-was-measuring-query-performance-at-different-degrees-of-parallelism"&gt;I Was Measuring Query Performance at Different Degrees of Parallelism&lt;/h2&gt;
&lt;p&gt;I set up a script to measure duration and wait statistics for a few queries. It followed this flow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set a variable with the &amp;ldquo;starter&amp;rdquo; degree of parallelism (DOP)&lt;/li&gt;
&lt;li&gt;Begin a loop
&lt;ul&gt;
&lt;li&gt;Clean up anything from the last round&lt;/li&gt;
&lt;li&gt;Record start time and snapshot of waits for the session from sys.dm_exec_session_wait_stats&lt;/li&gt;
&lt;li&gt;Run the test query at given DOP (using Dynamic SQL)&lt;/li&gt;
&lt;li&gt;Record end time and snapshot of waits for the session from sys.dm_exec_session_wait_stats&lt;/li&gt;
&lt;li&gt;Decrement the DOP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was gathering the data to graph and show query durations along with the amount of CXPACKET and CXCONSUMER waits at different DOPs.&lt;/p&gt;
&lt;h2 id="the-first-weird-thing-inconsistent-wait-stats"&gt;The First Weird Thing: Inconsistent Wait Stats&lt;/h2&gt;
&lt;p&gt;Whenever I can, I run a test more than once. I was graphing my wait statistics, and I noticed that on different executions of the procedure, my parallelism waits varied.&lt;/p&gt;
&lt;p&gt;Varied more than a small amount.&lt;/p&gt;
&lt;p&gt;Luckily for me, I read the release notes for Cumulative Updates for SQL Server most of the time, and after noticing the variation I remembered &lt;a href="https://support.microsoft.com/en-us/help/4057054"&gt;FIX: CXPACKET and CXCONSUMER wait types show inconsistent results for some parallel query plans in SQL Server 2017&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I checked, and sure enough, my little cloud VM was on SQL Server 2017 CU3, and that fix is in CU4.&lt;/p&gt;
&lt;p&gt;I patched to CU5 (latest and greatest for my little test instance, ya know), redid all my testing twice, and admired my now-more-consistent charts.&lt;/p&gt;
&lt;h2 id="the-second-weird-thing-inconsistent-query-duration"&gt;The Second Weird Thing: Inconsistent Query Duration&lt;/h2&gt;
&lt;!-- TODO: Image missing: /images/Cat-Binoculars-300x300.png --&gt;
&lt;p&gt;I was getting consistent results for query duration when I ran the query in the script above, which started at a high degree of parallelism, and then went to low.&lt;/p&gt;
&lt;p&gt;But I found that for one of my test queries, when I took the query and ran it in my own session to look at Query Time Stats in the execution plan, it took &lt;em&gt;much&lt;/em&gt; longer.&lt;/p&gt;
&lt;p&gt;For example, at MAXDOP 13:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duration was consistently 55-65 seconds in the looping script&lt;/li&gt;
&lt;li&gt;Running it in a session by itself, I was seeing durations of 2 minutes to 2 minutes 30 seconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More than twice as long.&lt;/p&gt;
&lt;p&gt;Why was it so much slower when I ran it in another session?&lt;/p&gt;
&lt;h2 id="it-wasnt-about-cachebuffer-pool-reuse"&gt;It Wasn&amp;rsquo;t About Cache/Buffer Pool Reuse&lt;/h2&gt;
&lt;p&gt;I had plenty of memory on this instance, and I&amp;rsquo;d made sure to set &amp;lsquo;max server memory (mb)&amp;rsquo; plenty high, but could something be causing me to do physical reads when I ran the query in my own session?&lt;/p&gt;
&lt;p&gt;This made me realize that my test script wasn&amp;rsquo;t quite fair to the DOP that ran first &amp;ndash; it might have to do physical reads where following queries made use of data in memory. This is a private test instance, so I changed the script to run everything with cold cache, by dropping clean buffers between runs.&lt;/p&gt;
&lt;h2 id="i-wasnt-getting-a-different-query-execution-plan"&gt;I Wasn&amp;rsquo;t Getting a Different Query Execution Plan&lt;/h2&gt;
&lt;p&gt;I was getting the same plan with the same cost both in my &amp;ldquo;slow session&amp;rdquo; and in the script.&lt;/p&gt;
&lt;h2 id="it-wasnt-async_network_io_waits"&gt;It Wasn&amp;rsquo;t ASYNC_NETWORK_IO_WAITS&lt;/h2&gt;
&lt;p&gt;I was running everything from an SSMS instance on my laptop against a SQL Server on a VM in the Azure Cloud. Could I be getting some weird kind of latency on one session?&lt;/p&gt;
&lt;p&gt;Nope. And my query wasn&amp;rsquo;t even returning a result set to my SSMS window &amp;ndash; it was putting the results into a table in the cloud.&lt;/p&gt;
&lt;h2 id="was-it-the-dynamic-sql"&gt;Was It the Dynamic SQL?&lt;/h2&gt;
&lt;p&gt;Could something about the Dynamic SQL be making it faster? Or had I made some sort of typo and the Dynamic SQL query was a little bit different in a way that made it faster?&lt;/p&gt;
&lt;p&gt;Nope, it really was the same query, and the same plan. When I copied the longer script and adjusted the variables to only run for DOP 13 in my &amp;ldquo;slow&amp;rdquo; session, it was also slow.&lt;/p&gt;
&lt;h2 id="was-it-using-statistics-time-or-statistics-io"&gt;Was It Using STATISTICS TIME or STATISTICS IO?&lt;/h2&gt;
&lt;p&gt;I sometimes use these to measure queries, but in this case I wasn&amp;rsquo;t using them in either session.&lt;/p&gt;
&lt;h2 id="was-it-having-actual-execution-plans-on"&gt;Was It Having Actual Execution Plans On?&lt;/h2&gt;
&lt;p&gt;Yes, it was.&lt;/p&gt;
&lt;p&gt;This query was a reminder of the observer effect: watching something can change its behavior. In this case, &amp;ldquo;watching&amp;rdquo; the query by enabling actual execution plans made it take twice the duration.&lt;/p&gt;
&lt;p&gt;I had actual plans enabled in my &amp;ldquo;slow&amp;rdquo; session, and I didn&amp;rsquo;t have them on in the session where I was measuring duration and wait statistics in the loop. (If you&amp;rsquo;ve ever accidentally left actual plans enabled when you&amp;rsquo;re running TSQL in a loop, you know how much SSMS doesn&amp;rsquo;t love that.)&lt;/p&gt;
&lt;p&gt;I tested this a few different ways, including in another instance of SSMS local to the VM itself, and sure enough - actual plan drags this puppy down, although it&amp;rsquo;s a relatively simple query.&lt;/p&gt;
&lt;h2 id="was-it-only-graphical-plans"&gt;Was It Only Graphical Plans?&lt;/h2&gt;
&lt;p&gt;I disabled graphical execution plans in Management Studio, then tested a few varieties of outputting actual plan info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SET STATISTICS XML ON - Actual plan information output as XML in a column named &amp;ldquo;Microsoft SQL Server 2005 XML Showplan&amp;rdquo;&lt;/li&gt;
&lt;li&gt;SET STATISTICS PROFILE ON - Actual plan information output as text across a variety of columns (screenshot below)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tested these independently. Both of these had the same impact on the query as using the graphic execution plan - the query took twice as long.&lt;/p&gt;
&lt;p&gt;I did feel kind of fancy looking at actual plan info in text format, though. We all know that hackers ALWAYS use text interfaces.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/set-statistics-profile-on.png"&gt;
&lt;/figure&gt;
&lt;em&gt;Kinda cool how execution count pops out in this view&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-about-live-query-statistics"&gt;What About &amp;lsquo;Live Query Statistics&amp;rsquo;?&lt;/h2&gt;
&lt;p&gt;I expected this to take a full three minutes, but it only took a bit longer than the &amp;lsquo;Actual Plan&amp;rsquo; run in this case: 2 minutes 5 seconds.&lt;/p&gt;
&lt;h2 id="does-this-happen-against-different-instances-at-different-dops"&gt;Does This Happen Against Different Instances? At Different DOPs?&lt;/h2&gt;
&lt;p&gt;I ran the same query against the same data on a local test VM on my MacBook Pro, which has 4 cores.&lt;/p&gt;
&lt;p&gt;The duration at MAXDOP 4 on the MacBook Pro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No actual execution plans = 2:41&lt;/li&gt;
&lt;li&gt;Actual execution plans enabled = 2:50&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hmm, the discrepancy is much smaller on the small instance.&lt;/p&gt;
&lt;p&gt;So I retested at MAXDOP 4 on the cloud VM. Note that this gets a different plan - similar shapes, but different costs (much more memory on that instance).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No actual execution plans =  2:20&lt;/li&gt;
&lt;li&gt;Actual execution plans enabled = 3:07&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To recap what I mentioned above, MAXDOP 13 on the cloud VM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No actual execution plans =  0:55&lt;/li&gt;
&lt;li&gt;Actual execution plans enabled = 2:00&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just for fun, MAXDOP 16 on the cloud VM (just in case you thought the issue was 13 being unlucky)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No actual execution plans =  1:00&lt;/li&gt;
&lt;li&gt;Actual execution plans enabled = 2:14&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Did I mention I&amp;rsquo;m compulsive about investigating this? MAXDOP 20 on the cloud VM (all its cores):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No actual execution plans =  1:12&lt;/li&gt;
&lt;li&gt;Actual execution plans enabled = 2:10&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Innnnnteresting. The impact of having actual plans enabled for this query is more pronounced on the cloud VM. The skew is greater at a higher DOP, although it&amp;rsquo;s not linear.&lt;/p&gt;
&lt;h2 id="actual-plans-are-awesome-but-make-sure-they-dont-confuse-your-tuning-process-by-secretly-skewing-your-execution-times"&gt;Actual Plans Are Awesome, but Make Sure They Don&amp;rsquo;t Confuse Your Tuning Process by Secretly Skewing Your Execution Times!&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s always overhead to using an actual plan.&lt;/p&gt;
&lt;p&gt;Frequently it&amp;rsquo;s minimal, but sometimes it&amp;rsquo;s &lt;em&gt;really&lt;/em&gt; significant - and the amount it varies may differ on different hardware, and at different degrees of parallelism.&lt;/p&gt;</description></item><item><title>Free Webcast: DBA vs Memory Settings</title><link>https://kendralittle.com/2018/04/11/upcoming-free-webcast-dba-vs-memory-settings/</link><pubDate>Wed, 11 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/11/upcoming-free-webcast-dba-vs-memory-settings/</guid><description>&lt;p&gt;Join me in two weeks for a really fun free webcast.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/DBA-vs-Memory-Settings-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Update: watch the &lt;a href="https://www.quest.com/webcast-ondemand/dba-vs-memory-settings8131810/"&gt;recording of the webcast here&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="dba-vs-memory-settings"&gt;DBA vs Memory Settings&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Tues, April 24, 2018 - 8:30AM Pacific / 11:30AM Eastern&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://www.quest.com/event/dba-vs-memory-settings8131382/"&gt;Quest Free Webcast - watch the recording here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;External memory pressure: What is it and how does it affect SQL Server?&lt;/p&gt;
&lt;p&gt;In this session, I am teaming up with SQL Server expert Jason Hall from Quest to play around with various configurations of Max Server Memory, Min Server Memory and Lock Pages in Memory and watch SQL Server squirm – for science!&lt;/p&gt;
&lt;p&gt;You’ll come away with a fresh understanding of how to configure major memory settings for SQL Server.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.quest.com/event/dba-vs-memory-settings8131382/"&gt;Watch this free session here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Register for My Free Session on Execution Plan Forcing</title><link>https://kendralittle.com/2018/04/09/register-for-my-free-session-on-execution-plan-forcing/</link><pubDate>Mon, 09 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/09/register-for-my-free-session-on-execution-plan-forcing/</guid><description>&lt;p&gt;I am excited to be giving a free online session as part of the &lt;a href="http://www.idera.com/lp/idera-live-virtual-conference-2018"&gt;Idera Live Virtual Conference, 2018&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Here are the details on &lt;a href="https://register.gotowebinar.com/register/6138150495442421251"&gt;my session&lt;/a&gt;:&lt;/p&gt;
&lt;h2 id="to-force-plans-or-not-to-force-plans-that-is-the-question"&gt;To Force Plans, or Not to Force Plans, That Is the Question&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://register.gotowebinar.com/register/6138150495442421251"&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/To-Force-Plans-or-Not-to-Force-Plans-That-is-the-Question-2.jpg"&gt;
&lt;/figure&gt;
&lt;/a&gt;Wed, May 16, 2018 - 9AM Pacific / Noon Eastern&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We have new ways to force execution plans in SQL Server: in SQL Server 2017, you can even let SQL Server temporarily force query plans for you and test if it works well!&lt;/p&gt;
&lt;p&gt;In this session, you&amp;rsquo;ll learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How forcing plans with Query Store compares with the older technology of Plan Guides&lt;/li&gt;
&lt;li&gt;How to tell when a plan has been forced&lt;/li&gt;
&lt;li&gt;What &amp;ldquo;morally equivalent plans&amp;rdquo; are (and why they&amp;rsquo;re a good thing)&lt;/li&gt;
&lt;li&gt;How to see if a query has a high variation in performance&lt;/li&gt;
&lt;li&gt;How to decide, &amp;ldquo;Should I force this plan?&amp;rdquo; and &amp;ldquo;Should I let SQL Server force plans for me?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://register.gotowebinar.com/register/6138150495442421251"&gt;Register for this free session here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="but-wait-theres-more"&gt;But Wait, There&amp;rsquo;s More&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not the only one giving cool sessions that day &amp;ndash; &lt;a href="http://www.idera.com/lp/idera-live-virtual-conference-2018"&gt;check out more free sessions at the Idera Live Virtual Conference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope to see you there!&lt;/p&gt;</description></item><item><title>Dear SQL DBA: I Want to Work for Myself (video with captions and transcript)</title><link>https://kendralittle.com/2018/04/06/dear-sql-dba-i-want-to-work-for-myself-video-with-captions/</link><pubDate>Fri, 06 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/06/dear-sql-dba-i-want-to-work-for-myself-video-with-captions/</guid><description>&lt;p&gt;Our question this week comes from an IT pro who would like to be self-employed. In this episode, I talk about three big things you need to think about to start working for yourself, and two possible paths to get there.&lt;/p&gt;
&lt;h2 id="subscribe"&gt;Subscribe&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d rather listen on the go, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;subscribe on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;amp;isi=691797987&amp;amp;ius=googleplaymusic&amp;amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;listen on Google Play&lt;/a&gt;, or plug this URL into your favorite podcasting app: &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;http://dearsqldba.libsyn.com/rss#&lt;/a&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/p92Gsd4syto?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h1 id="transcript"&gt;Transcript&lt;/h1&gt;
&lt;p&gt;Welcome to the Dear SQL DBA podcast and YouTube show. I&amp;rsquo;m Kendra Little. On today&amp;rsquo;s podcast, our topic is Dear SQL DBA: I Want To Work For Myself.&lt;/p&gt;
&lt;p&gt;For the Dear SQL DBA podcast, I take questions from folks, database administrators and developers usually, and they give me all sorts of questions.&lt;/p&gt;
&lt;p&gt;This one is someone who said,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I currently work for a larger corporation as a consultant. There are lots and lots of processes, and all of the tickets I work on are emergencies and I&amp;rsquo;m getting really burnt out. &amp;ldquo;I have an IT focus. Is it possible to get a job like a freelance developer but with an IT focus?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a question that, it&amp;rsquo;s a great question, and more and more freelancers find different ways to do their jobs but freelancing isn&amp;rsquo;t easy. I will mostly be focusing on working for yourself in The United States today. There&amp;rsquo;s different people who do this around the world and with different healthcare systems and different tax laws, it does vary.&lt;/p&gt;
&lt;p&gt;My experience with this is all in The United States, and in The United States, freelancing isn&amp;rsquo;t easy. I don&amp;rsquo;t get the impression that it&amp;rsquo;s super easy anywhere but we do have some of our specific challenges.&lt;/p&gt;
&lt;h2 id="three-big-questions"&gt;Three Big Questions&lt;/h2&gt;
&lt;p&gt;One of the big things to look at first when you&amp;rsquo;re thinking about starting to work for yourself is three big questions.&lt;/p&gt;
&lt;p&gt;What are the products or services I&amp;rsquo;m going to sell? When I say products here, I really mean what am I selling? They may be all service based. There may be some product I actually deliver something, but what am I going to sell? Who am I going to sell it to and then how will I go about running the business? So, we&amp;rsquo;re going to dig into each of these three things because before you get started, you need to know what you want to do with all of these.&lt;/p&gt;
&lt;h2 id="what-do-i-want-to-sell"&gt;What Do I Want to Sell?&lt;/h2&gt;
&lt;p&gt;Will I build some tools that I will need to do my services or am I going to sell these tools to people? What types of processes do I need to build my services? Even for an initial consulting job, what kinds of scripts do I want to use? I can&amp;rsquo;t just use anyone&amp;rsquo;s code from the internet. I need to look at their licensing.&lt;/p&gt;
&lt;p&gt;What kind of tools do I want to use for the product that I&amp;rsquo;m offering, how long is it going to take me to set up that initial offering? What do these products cost?&lt;/p&gt;
&lt;p&gt;And are there products I can sell that once I build them first, they will continue to make money for me without me actively being involved in them? This isn&amp;rsquo;t always the case but sometimes, there are products you can build where for an initial effort, those products can continue to generate money with relatively low maintenance or input on your part, where all of the work is done by a tool you built, perhaps. It could be a variety of things but you&amp;rsquo;re not going to have to be personally delivering the product. Sometimes that&amp;rsquo;ll be a yes, sometimes that&amp;rsquo;ll be a no, but you really just want to know the answers for these.&lt;/p&gt;
&lt;h2 id="who-are-my-customers"&gt;Who Are My Customers?&lt;/h2&gt;
&lt;p&gt;And then in terms of who you&amp;rsquo;re going to sell them to, there&amp;rsquo;s different ways to find your customers.&lt;/p&gt;
&lt;p&gt;Some businesses run on customers that find them and come to them and maybe this works based on a blog, or maybe there are free tools that are given out. For instance, these days I write a free quiz every week. I have quizzes on my website, I also blog on my business website, I give away some courses for free.&lt;/p&gt;
&lt;p&gt;Doing these things so that when people are having a problem and they search in a search engine on the internet, you want to have them finding blog posts by you, or finding tools that you have if you want to have this type of relationship where the customer starts using your tools and then there&amp;rsquo;s perhaps something else that they can upgrade to that costs money with you. It takes a while to build up a following so that enough people are finding you, right? We have to start and we have to build this up.&lt;/p&gt;
&lt;p&gt;There are businesses, however, where it&amp;rsquo;s marketing is done by, okay, we&amp;rsquo;re going to identify the customers, we&amp;rsquo;re going to purchase a mailing list from someone or we&amp;rsquo;re going to purchase a list of potential customers from someone and then we are going to reach out to these people. Course, we have to figure out how are we going to identify with them, who is going to be going out and engaging with them, how much time is that going to take?&lt;/p&gt;
&lt;p&gt;And then we design, after we figure out, okay, who are our customers and how are we going to connect with them, we have to design a sales pipeline. Because we want to qualify our sales prospects. Depending on what you&amp;rsquo;re selling them, and in fact, I would say in general, there&amp;rsquo;s very few businesses where you want to sell your product to just anyone.&lt;/p&gt;
&lt;p&gt;You want to sell your product to people who are going to find it useful. Because you know, selling something to someone that&amp;rsquo;s totally useless for them is going to get you bad reviews and unhappy customers. So, you need to have a process for your customers that you&amp;rsquo;ve identified to help say, &amp;ldquo;Is this right for you?&amp;rdquo; And we&amp;rsquo;re going to bring you down through the pipeline.&lt;/p&gt;
&lt;p&gt;You want to think about when you&amp;rsquo;re working for yourself&amp;ndash; one of the inherent problems with working for yourself, especially if you&amp;rsquo;re doing something like consulting is are you trying to land really large projects, or are you trying to work on a lot of different projects? How many customers do you want to have? If you want to do the kind of business where you&amp;rsquo;re working really with one or two customers at a time, the problem with running a company like that is that you become really, really dependent upon those customers, and this isn&amp;rsquo;t just tiny companies.&lt;/p&gt;
&lt;p&gt;I worked for a software company with 100 people at one point where most of our revenue came from one really large customer. And when that customer says jump, it&amp;rsquo;s really hard to say it&amp;rsquo;s not a good idea to jump right now, because if they leave, there goes a huge amount of your revenue stream. It can be done, it puts you into different situations in terms of your relationship with that customer. And these are all things that we&amp;rsquo;re talking about.&lt;/p&gt;
&lt;p&gt;You can change these over the life of your business. What we&amp;rsquo;re talking about here is saying for the initial offering that I want to set up, what do I want to do?&lt;/p&gt;
&lt;h2 id="how-do-i-run-the-business"&gt;How Do I Run the Business?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s also a lot to think about just as to what business do I want to form? Am I going to have partners? How am I going to incorporate this legally? In The United States, you can do this as an LLC, you can do this as an S corp, there&amp;rsquo;s a lot of different ways. Put some time into researching what these different things mean, and figuring out what you want to do.&lt;/p&gt;
&lt;p&gt;You also have to decide how much money you want to invest to get started. Because especially if this is something you&amp;rsquo;re going to jump into full-time without a customer pipeline, you&amp;rsquo;re going to burn through money.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re not going to have a lot of income coming in unless you get really, really lucky. So, you have to figure out how much am I going to invest and how much risk will I tolerate? Even in small business where things are going well, and you do have good income for a while, there can be these dry spells. It may be based on time of year, depending on the industry you&amp;rsquo;re using, it may just be a coincidence. I&amp;rsquo;ve actually seen in the consulting business that there are seasonal dips in consulting where people are like, &amp;ldquo;Oh, well, it&amp;rsquo;s summer vacation, &amp;ldquo;and everybody&amp;rsquo;s going out with their kids, &amp;ldquo;we don&amp;rsquo;t want to do a lot of research into changing things. &amp;ldquo;we&amp;rsquo;re just keeping the staff around &amp;ldquo;just to keep things steady.&amp;rdquo; If you&amp;rsquo;re providing more sustaining, regular services for people, that might actually be your higher period if people are out of the office and they want you there to help sustain things.&lt;/p&gt;
&lt;p&gt;So, depending on what your industry is, there are going to be periods where things wax and wane and you do need to work that into your risk calculation. When you&amp;rsquo;re working for yourself, you can&amp;rsquo;t count on always getting the same paycheck for the right amount coming in. Do you want to have people who contract as your employees? Do you want to have employees? Especially in the initial years of your business, it&amp;rsquo;s a big decision, and then just, how am I going to run things?&lt;/p&gt;
&lt;p&gt;How will I keep track of who my customers are, their contact details, how I have engaged with them, how likely I think they are to buy a service? There&amp;rsquo;s tools you can use for this, you may want to start using something simple, and then grow, depending on what kind of potential customers you&amp;rsquo;re starting with, you may need a more complex tool if you actually already have a good base of prospects that maybe you&amp;rsquo;ve purchased from someone or have some way to access. Need to find ways to invoice people and to track our expenses, very important. We need to do bookkeeping and accounting, and there&amp;rsquo;s just a lot of mundane little things that come with doing your own thing. Like not only invoicing people, but following up and saying, &amp;ldquo;Hey, I need to get paid.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So, there&amp;rsquo;s lots and lots of different things to start with just on running the business side. How do I get to this path though, right? I need to think about my products, I need to think about my customers, I need to think about how to run the business.&lt;/p&gt;
&lt;h2 id="path-1-the-expert"&gt;Path #1: The Expert&lt;/h2&gt;
&lt;p&gt;But okay, how do I even get the ability to attract the customers? There&amp;rsquo;s a couple different paths that I&amp;rsquo;ve seen folks take to this and I&amp;rsquo;m going to outline two of them.&lt;/p&gt;
&lt;p&gt;We have a question that fits right in with the first path. The question is, &amp;ldquo;How do you stand out from the other more experienced consulting folks?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s talk about this in the path to the expert. One way to become a successful freelancer is to figure out: these are the problems I want to solve, these are the products I want to sell, and my customers will want to buy them because they want to do something faster, or there&amp;rsquo;s something they can&amp;rsquo;t do that I will enable them to do. Or they won&amp;rsquo;t have to have as, they&amp;rsquo;ll be able to save costs in some way. Once you identify what this really is, you can work towards becoming an expert and really focus on, especially these things that you want to offer.&lt;/p&gt;
&lt;p&gt;Now, you&amp;rsquo;re not going to dive in with this path. Folks following this path tend to say, okay, I want to work for myself.&lt;/p&gt;
&lt;p&gt;One of the first steps to doing that is I need to learn how you&amp;rsquo;re going to run this business. I need to learn how to attract these customers so I&amp;rsquo;m going to find a small to medium sized business doing something similar to what I want to do, at least in that industry, and I want to work there for a while. I want to learn from them, how they are running and growing that business, and what works and what doesn&amp;rsquo;t, and while I work there, I am going to build up a personal blog and a lot of my own intellectual property, and when I&amp;rsquo;m doing this on my own time, this is not part of the company, this thing I&amp;rsquo;m doing on my own time, when I&amp;rsquo;m doing this, I&amp;rsquo;m really going to focus about building up information that is related to the services or products that I plan to offer.&lt;/p&gt;
&lt;p&gt;That intellectual property that you&amp;rsquo;re building up, speaking at conferences, doing that blog, is what is going to set you out once you eventually strike, it&amp;rsquo;s going to set you apart rather, once you eventually strike out upon your own as an expert and it&amp;rsquo;s really that focus on exactly what you offer and your approach to it that is going to set you apart. So, you want to have some personality in there and you want, maybe this is going to give you a, depending on what you want to deliver to people, maybe this is going to give you a focus on, okay, I&amp;rsquo;ll include some short video clips so if I want to do consulting, so they get a sense of what it&amp;rsquo;s like to talk to me, for example.&lt;/p&gt;
&lt;p&gt;Or, if you&amp;rsquo;re going to offer something more automated, maybe you want to start building small example services or building small examples of the types of things that you want to do.&lt;/p&gt;
&lt;p&gt;There are things we have to really look out for in this path and you have to be careful though. When you&amp;rsquo;re working at a small to medium firm, I mean most of the times, there&amp;rsquo;s going to be an agreement that says, &amp;ldquo;Hey, if you leave us, you can&amp;rsquo;t take our customers with you.&amp;rdquo; I&amp;rsquo;m not going to get into arguing about legal enforceability. You really don&amp;rsquo;t want to be stealing customers anyway. I&amp;rsquo;m not saying to get a job at one of these small businesses so that when you go work on your own, you can take the clients, because usually, that is going to light a giant bridge on fire and cause a ton of problems.&lt;/p&gt;
&lt;p&gt;I would be pretty open in the interview with a company like this saying, I would perhaps, because at this point, when you&amp;rsquo;re getting the job for the company, you don&amp;rsquo;t know. I mean, you may find that you really like working at this little company and you&amp;rsquo;re like, &amp;ldquo;I don&amp;rsquo;t need to go work for myself, this is actually so rewarding, I don&amp;rsquo;t want to deal with all that accounting and bookkeeping, this is better.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But I would be open if you are thinking about maybe doing something yourself someday. I would be actually open about that and honest about that because in your relationship with that employer, you don&amp;rsquo;t want to have a big giant secret that you&amp;rsquo;re hiding, in my opinion.&lt;/p&gt;
&lt;p&gt;Also, that opens up the door to have a conversation with them that says, &amp;ldquo;If I&amp;rsquo;m writing blog posts on my own time, who do those belong to?&amp;rdquo; You want it to be very clear if you&amp;rsquo;re on the side building up a presence for yourself, you want it to be very, very clear that you own that intellectual property.&lt;/p&gt;
&lt;p&gt;Same thing with talks that you write for conferences. You want to know exactly which ones you own and exactly which ones your employer owns. Because if there&amp;rsquo;s a point where you do set out on your own and you start using these materials, you really don&amp;rsquo;t want to get hit with legal problems at that point when you&amp;rsquo;re just starting out your own company.&lt;/p&gt;
&lt;p&gt;So, I would negotiate for is it okay for me to own this intellectual property that I write, who owns that?&lt;/p&gt;
&lt;p&gt;I would raise the question, and make sure you clearly know the answer to, is it okay for me to moonlight on something? Can I take on clients on my own in hours outside of working hours that are totally separate, can I do work on my own and get paid for that? This includes even, like if you do say a pre-conference session at a conference, these are paid engagements, and so, knowing that even helps, yes, you&amp;rsquo;re taking on outside employment, is that something that they don&amp;rsquo;t allow? Because if so, you may not want to work for them if you really are setting the stage to go work on your own. So that&amp;rsquo;s Path A, or Path 1. I should stick with the numbering system.&lt;/p&gt;
&lt;h2 id="path-2-the-side-hustle"&gt;Path #2: The Side Hustle&lt;/h2&gt;
&lt;p&gt;The second path is the side hustle because on Path 1 we were really, we&amp;rsquo;re doing some blogging on our spare time, but we weren&amp;rsquo;t really doing moonlighting in our spare time. And maybe it comes up when it comes to conference talk, but we really working a second job. The second path to this isn&amp;rsquo;t really becoming an expert. The second path for this is working a lot to make it happen, and by a lot, I do mean a lot, there are folks who do this.&lt;/p&gt;
&lt;p&gt;Starting a second business in your spare time and scoping your products to fit it to make sure that okay, I am working multiple jobs. If my customer needs me and I&amp;rsquo;m working my main job, I need to have a way that that&amp;rsquo;s okay, where they don&amp;rsquo;t need an immediate response or maybe I have some job where I can stop working it for a while, most IT jobs aren&amp;rsquo;t like that, they&amp;rsquo;re full-time jobs, right? Usually, we commit to these certain hours but you need to find a way to make sure that for your side gig that okay, I&amp;rsquo;m only available during a certain time, or there&amp;rsquo;s a long enough response time, a long enough service level agreement for you to not be available right away, typically.&lt;/p&gt;
&lt;p&gt;So, you start off doing something nights and weekends, you scope your products to fit with that, and you use that experience to refine your product and figure out what works really well, to build up testimonials from your customers, to get all your processes set, to get your accounting set, &amp;lsquo;cause you&amp;rsquo;re doing this in your spare time and as you&amp;rsquo;re scaling up your business, you&amp;rsquo;re saying, I&amp;rsquo;m going to get to certain point where I can leave that original gig and do this side gig full-time.&lt;/p&gt;
&lt;p&gt;Again with this one, you really have to make sure that you&amp;rsquo;re not secretly doing that work &amp;lsquo;cause you&amp;rsquo;re employer is going to find out. The more successful your side gig gets, the emplo&amp;ndash; But also, you need to be able to be open about this. You need to be able to have a with and say, hey, you know, this is what I do and this is how I do it well to be open with not only your existing customers but to have a way to communicate with potential customers.&lt;/p&gt;
&lt;p&gt;The biggest problem with this is also that it&amp;rsquo;s really hard, it&amp;rsquo;s really time consuming because we&amp;rsquo;re dependent upon the revenue from our initial job. While we&amp;rsquo;re building up the new one, we are literally rebuilding our career as we are working it.&lt;/p&gt;
&lt;h2 id="what-about-contracting"&gt;What About Contracting?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve had some folks ask me also what about contracting, can contracting be a stepping stone to make this process easier? I personally have been a contractor before. I was a contractor at Microsoft and these terms for folks outside The United States, these terms might work a little bit differently. In The United States, typically, a contractor works for an agency, the agency has a bunch of clients and they hire on contractors for short to medium term engagements, the contracting company takes a cut of your income and typically in The United States, you earn an hourly rate, you may or may not get any benefits for this, so you may still be buying your own health insurance separate from that.&lt;/p&gt;
&lt;p&gt;The thing about my contracting gig is I actually, for me, it ended up in me getting a full-time job at Microsoft. At that time in my career, what I really wanted was a &amp;ldquo;real DBA job.&amp;rdquo; I wanted to be a full-time DBA working on production systems. I&amp;rsquo;d essentially been a junior DBA and only gotten to work in non-production systems up to that point. And I got this contract gig, and I also was like, I wasn&amp;rsquo;t sure what it would be like to work at Microsoft. I wasn&amp;rsquo;t sure if I&amp;rsquo;d like it, so it was kind of, you know, like a good short term opportunity to do that, and I could sustain risk at that point. Like if it didn&amp;rsquo;t work out, I could pick up another contract, I was okay with that, and my only dependent was a giant rabbit at that time. So, relatively low risk. It ended up getting a full-time job at Microsoft.&lt;/p&gt;
&lt;p&gt;Looking back on it, it would not have been a good job in terms of going out to work on my own because I hadn&amp;rsquo;t negotiated a great rate. And a lot of that was I didn&amp;rsquo;t even know how to negotiate, and not knowing how to negotiate is a hindrance to when you&amp;rsquo;re working for yourself. I just wasn&amp;rsquo;t ready at that time. Also, I worked a lot of hours for that job and I needed to be available to work an on-call schedule that could be very erratic. And if I had tried to do that job and another job at the same time, I would have gotten burnt out. So, it just would not, that contracting job wouldn&amp;rsquo;t have worked for that.&lt;/p&gt;
&lt;p&gt;If you can do contracting in a way where you can negotiate a really, a good rate, that allows you to, within a limited scoping hours of work, say okay, I&amp;rsquo;m earning enough here that I can do a side hustle, or I&amp;rsquo;m earning enough here that I have time to blog. I have time to build up my expertise, and this contracting job allows me to go on the expert path, you can do this.&lt;/p&gt;
&lt;p&gt;But you really want to make sure that it is the type of job that isn&amp;rsquo;t going to burn you out. Then here&amp;rsquo;s the other thing, with contracting jobs, the contract can come to end at any time. The reason this is attractive to employers is you&amp;rsquo;re not a full-time employee. So, if they run out of budget, your gone. So, the biggest problem I think with contracting is you get the sort of uncertainty of what is my paycheck going to be next month? Without the benefits of working for yourself. You might be able to fit it in with this, but I don&amp;rsquo;t think it&amp;rsquo;s a magical way to speed up the process if that helps, it&amp;rsquo;s another job, but it&amp;rsquo;s a job with some uncertainty built into it. So, it can be a little tougher than having a more predictable full-time job if you&amp;rsquo;re trying to do the side hustle route.&lt;/p&gt;
&lt;h2 id="i-know-this-sounds-hard-and-may-sound-a-little-bit-discouraging-but-it-is-hard-theres-a-reason-that-not-everyone-is-doing-this"&gt;I Know This Sounds Hard and May Sound a Little Bit Discouraging. But It Is Hard. There&amp;rsquo;s a Reason That Not Everyone Is Doing This.&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a reason that you see people strike out on their own and then take a job at a full-time company again. It doesn&amp;rsquo;t always work well, and you will, when running your own business, you will have to go through a process of saying, &amp;ldquo;Oh, this didn&amp;rsquo;t work out. I wasn&amp;rsquo;t charging enough money for this / I need to change my product or I need to raise my rates,&amp;rdquo; or, &amp;ldquo;I&amp;rsquo;ve lost clients and I need &amp;ldquo;to figure out a way to find new ones,&amp;rdquo; or, &amp;ldquo;I goofed up at this client. I need to see if I can save this relationship with my client and they may leave me.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Goofing up may or may not be your fault. Goofing up can be a communication thing. It could have been a problem with a contract, it could have been in part someone else&amp;rsquo;s fault who works with the client, right? But things are going to happen and mistakes are going to be made, that&amp;rsquo;s just life.&lt;/p&gt;
&lt;p&gt;So, you constantly have to be really persistent when working for yourself and say, &amp;ldquo;Okay, how can I make this better?&amp;rdquo; And &amp;ldquo;How can I get past this?&amp;rdquo; So, it&amp;rsquo;s hard, and there is a path from being really burnt out to being a consultant who works for themselves.&lt;/p&gt;
&lt;h2 id="the-first-thing-i-would-do-is-address-the-burnout-problem"&gt;The First Thing I Would Do Is Address the Burnout Problem&lt;/h2&gt;
&lt;p&gt;The problem of I am working for someone else and I am really burnt out, this is not something you want to start a company from, &amp;lsquo;cause it&amp;rsquo;s a hard process.&lt;/p&gt;
&lt;p&gt;Starting something really hard isn&amp;rsquo;t going to solve your burn out. So the first step I think is actually figuring out I need to get into a place where I&amp;rsquo;m not unhappy, because either becoming an expert or doing the side hustle, having your main job making you really stress out and unhappy, not going to help you succeed on this path.&lt;/p&gt;
&lt;p&gt;So, you may need to change your job, you may need to change your habits. Exercise, sleep, how you handle stress. You may need to change things in your personal life, you may need to work on your ability to say no to people and to be able to explain to your manager, &amp;ldquo;Okay, here&amp;rsquo;s why I can&amp;rsquo;t work every night, &amp;ldquo;and here&amp;rsquo;s what we&amp;rsquo;re going to do to solve this problem.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Because when you start your own company, all these things that stress you out, of all of my customers think their issue is number one, or I have to give someone bad news, or we can&amp;rsquo;t make this deadline because there&amp;rsquo;s 18 things about this project you didn&amp;rsquo;t tell me about, things you will have to constantly deal with, things that are out of your control causing you problems when you work for yourself.&lt;/p&gt;
&lt;p&gt;And yes, as someone who works for yourself, you do have the ability to say, &amp;ldquo;Okay, I don&amp;rsquo;t want to do this work,&amp;rdquo; and we&amp;rsquo;re going to end this relationship with my customer, but it comes with a very clear financial penalty and you have to be able to work through that and you have to be able to work through the things where things don&amp;rsquo;t work out and we have to start over again without it causing stress and burnout.&lt;/p&gt;
&lt;h2 id="the-truth-is-that-being-your-own-boss-can-mean-having-a-terrible-boss"&gt;The Truth Is That Being Your Own Boss Can Mean Having a Terrible Boss&lt;/h2&gt;
&lt;p&gt;You know, my boss doesn&amp;rsquo;t go away on the weekend. She&amp;rsquo;s there with me in the morning, she&amp;rsquo;s there with me late at night, and sometimes, she just won&amp;rsquo;t shut up about all the stuff she wants me to do and she wants to know why I haven&amp;rsquo;t gotten it done yet. That is the truth about working for yourself.&lt;/p&gt;
&lt;p&gt;So, this thing of being burnt out really is important to solve in order to actually enjoy having your own company. And it may not be something you can solve immediately but it is really worth figuring that out and then, from a more healthy mental space of not being completely burnt out, figure out do I want to go more along this expert route and how am I going to find a small to medium sized company doing something similar to what I&amp;rsquo;m doing to work at and what is my plan to start trying to find these jobs, start trying to figure out what I can do to work for these folks?&lt;/p&gt;
&lt;p&gt;Or, do I want to do more of the side hustle gig and what is my plan to make that actually work in my life so that I can still sleep? So, I can still leave the house occasionally, and so, that I can really not get burnt out again. Really, really tough to figure it out but you absolutely can figure it out.&lt;/p&gt;
&lt;h2 id="psa-changes-in-webcasts"&gt;PSA: Changes in Webcasts&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve got another question that I&amp;rsquo;m going to hit up. Before I hit up the question, I do want to just say there have been some changes going on in terms of the webcast that I offer. I no longer offer free signups for my technical webcast. I&amp;rsquo;m going subscribers only on my technical webcast.&lt;/p&gt;
&lt;p&gt;But, there will be lots more Dear SQL DBA podcast episodes. Those are now free and open to everyone. So, in the next one, we&amp;rsquo;ll be talking about what the deal is with certifications in the next episode, also, do SQL DBAs need college degrees, and lots more stuff. So, I would love it if you can join me for any of the events going forward, but yeah, i have been changing things up.&lt;/p&gt;
&lt;h2 id="choosing-your-area-of-focus"&gt;Choosing Your Area of Focus&lt;/h2&gt;
&lt;p&gt;Like I said, you have to constantly reinvent things in order to keep things going. So, the question is, &amp;ldquo;What areas of SQL Server &amp;ldquo;do you think deserve attention nowadays &amp;ldquo;and therefore can be an area of expertise for exploration?&amp;rdquo; That&amp;rsquo;s a great question and really interesting things when it comes to SQL Server these days. There&amp;rsquo;s a lot, if you&amp;rsquo;re at all interested in cloud technologies, there&amp;rsquo;s a lot of momentum going still for what parts of our applications can we move to the clouds, to the cloud, it really is clouds because we may want to use more than one cloud, we may want to use more than one service, but can we move to the cloud, how much can it save us on cost? And things change rapidly in the cloud. So, becoming an expert on things as they emerge can be worthwhile.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s always a risk though that you&amp;rsquo;re going to learn something new with some new cloud technology that no one&amp;rsquo;s going to eventually adopt, maybe because it&amp;rsquo;s just too expensive, right? So, with all of these things, I do think that, yeah, if you&amp;rsquo;re looking at a new area to specialize in right now, and you want to do consulting and training, the cloud can be really interesting. The cloud is really hard for training though because of the rapid rate that it changes. And I do say if that&amp;rsquo;s something you&amp;rsquo;re interested in because I think you really have to like it and be interested in it for it to work. One example of where interest is, and aptitude as well, is really important is things like learning data science.&lt;/p&gt;
&lt;p&gt;So yes, learning data science, very, very interesting field, emerging great area for building expertise, but you have to like statistics and math and you have to be willing to kind of stick through it and see where it evolves and learn how what is offered in SQL Server compares to what&amp;rsquo;s offered elsewhere, right? I know some folks in a college-level course on artificial intelligence who got signed up for this course and, man, apparently it was just a whopper. &amp;ldquo;This sounds really cool!&amp;rdquo; And then near the end of the semester, everybody was just like&amp;hellip; &amp;ldquo;This, this is overwhelming!&amp;rdquo; Like, there&amp;rsquo;s literally a fire hose pointed at me. So, these areas really are taking off and really are getting a lot of interest, but&amp;hellip; Do look at your own&amp;hellip; And I don&amp;rsquo;t love working with statistics, for example, so I will not be going deep down the data science path just because I took a college course on statistics once and I did okay, but I really kind of dreaded doing my homework. It wasn&amp;rsquo;t something I looked forward to, so, whereas on the other hand, when I first started working with relational databases and queries in SQL Server, I just wanted to work on it all the time.&lt;/p&gt;
&lt;p&gt;So, if there&amp;rsquo;s areas where you&amp;rsquo;ve got, you know, people say don&amp;rsquo;t follow your passion. I kind of think that&amp;rsquo;s BS and I don&amp;rsquo;t know if it&amp;rsquo;s really like, &amp;ldquo;Follow your passion,&amp;rdquo; but I do think like if there&amp;rsquo;s things that you find really rewarding to do, if there&amp;rsquo;s some way you can figure out how to make money at it, even if it&amp;rsquo;s uncool, even if, you know, it&amp;rsquo;s not the newest greatest thing, see if you can make money doing that thing. Because you really like working with it and it&amp;rsquo;s your life! So, you know, I would consider that first, personally.&lt;/p&gt;
&lt;p&gt;I mean, if your passion is underwater basket weaving, there are places you can teach that, it turns out. There are ways to make a living out of that.&lt;/p&gt;
&lt;p&gt;So, yeah, part of that I would fit into is definitely aptitude, and I mean aptitude, not just as I&amp;rsquo;m automatically good at it, but aptitude as I&amp;rsquo;m interested enough in it to keep wanted to do it when it&amp;rsquo;s really hard because a lot of these things are really hard and we&amp;rsquo;ll have to keep at &amp;rsquo;em.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really that I like keeping at it and I really want to know it even though it kind of drives me crazy that it&amp;rsquo;s really hard. I don&amp;rsquo;t mean aptitude as something that&amp;rsquo;s just easy.&lt;/p&gt;
&lt;h2 id="thanks-for-attending-or-listening-to-this-live-podcast-session"&gt;Thanks for Attending or Listening to This Live Podcast Session&lt;/h2&gt;
&lt;p&gt;So thank you, folks, for showing up for this inaugural recorded episode, a live episode of the Dear SQL DBA podcast and thank you for the questions, those are awesome. I hope that you guys have a great day wherever you are and I will be back on April 18th.&lt;/p&gt;
&lt;p&gt;I personally am about to head to Hawaii with a bunch of my closest girlfriends, so I&amp;rsquo;m abandoning the homestead and Jeremiah will stay here while I head off to have some sun and fun with 16 of my favorite women friends, and I will then be back later to do lots more stuff with you guys. So thanks a bunch, have a great day, and I&amp;rsquo;ll see you soon. Thanks, guys!&lt;/p&gt;</description></item><item><title>Adaptive Queries in Standard Edition: Interleaved Exec for Multi-Statement TVFs</title><link>https://kendralittle.com/2018/04/04/adaptive-queries-in-standard-edition-interleaved-exec-for-multi-statement-tvfs/</link><pubDate>Wed, 04 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/04/adaptive-queries-in-standard-edition-interleaved-exec-for-multi-statement-tvfs/</guid><description>&lt;p&gt;It&amp;rsquo;s tough to keep track of which features work in each version of SQL Server, and which Editions support them.&lt;/p&gt;
&lt;p&gt;My memory told me that the new Adaptive Joins feature in SQL Server 2017 was Enterprise Edition only&amp;hellip;  and that&amp;rsquo;s correct, but I didn&amp;rsquo;t realize that the fancy new feature to make Multi-Statement TVFs smarter has much wider licensing.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Function-Beaver-Likes-Interleaved-Execution.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="interleaved-execution-for-multi-statement-table-valued-functions-works-in-enterprise-standard-web-and-express-editions"&gt;Interleaved Execution for Multi-Statement Table Valued Functions works in Enterprise, Standard, Web, and Express Editions&lt;/h2&gt;
&lt;p&gt;I discovered this by accident when I was doing some testing on my Standard Edition instance. I was looking at an execution plan, and I checked the properties of a TVF and &amp;hellip;&lt;/p&gt;
&lt;p&gt;First, I double-checked and made sure I really was connected to my Standard Edition instance. YEP.&lt;/p&gt;
&lt;p&gt;Then I checked the &lt;a href="https://docs.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2017"&gt;SQL Server 2017 Editions and Components&lt;/a&gt; chart to see if this was an accident or not&lt;/p&gt;
&lt;p&gt;Sure enough, &amp;lsquo;Batch Mode Adaptive Joins&amp;rsquo; and &amp;lsquo;Batch Mode Memory Grant Feedback&amp;rsquo; are Enterprise Edition features.&lt;/p&gt;
&lt;p&gt;&amp;lsquo;Interleaved Execution for Multi-Statement Table Valued Functions&amp;rsquo; is available in &lt;em&gt;all the editions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What does &amp;lsquo;Interleaved Execution for Multi-Statement TVFs&amp;rsquo; do for you?&lt;/p&gt;
&lt;p&gt;Multi-statement table valued functions are difficult to optimize as part of a query: they run multiple statements, so how the heck do you estimate how many rows are going to come out of that?&lt;/p&gt;
&lt;h2 id="this-new-feature-lets-the-optimizer-stop-and-take-a-peek"&gt;This New Feature Lets the Optimizer Stop and Take a Peek!&lt;/h2&gt;
&lt;p&gt;When the optimizer finds a multi-statement TVF that qualifies*, it &lt;em&gt;pauses the optimization process&lt;/em&gt; (badass!), and then goes briefly into the execution phase.&lt;/p&gt;
&lt;p&gt;(This is the interleaving part.) It can run through that little part of the plan to get a good estimate, instead of making a blind guess.&lt;/p&gt;
&lt;p&gt;Good estimates means a &lt;em&gt;much&lt;/em&gt; better chance that you&amp;rsquo;ll get the right joins, memory grant, and qualify for parallelism when needed.&lt;/p&gt;
&lt;p&gt;That usually adds up to faster query execution.&lt;/p&gt;
&lt;h2 id="which-multi-statement-tvfs-qualify"&gt;Which Multi-Statement TVFs qualify?&lt;/h2&gt;
&lt;p&gt;Not all multi-statement TVFs are created equal. If your TVF is part of a data modification, or if your TVF is inside a CROSS APPLY, it doesn&amp;rsquo;t qualify for this magic &amp;ndash; at least not in SQL Server 2017. That may change in the future, this is just the V1.&lt;/p&gt;
&lt;h2 id="how-do-i-turn-this-on"&gt;How Do I Turn This On?&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re on SQL Server 2017, your database compatibility level controls whether or not this feature is available.&lt;/p&gt;
&lt;p&gt;If your compat mode is 140, your multi-statement table valued functions are very likely to speed up.&lt;/p&gt;
&lt;p&gt;I say &amp;lsquo;very likely&amp;rsquo; because there can be some edge cases where better estimates lead to worse performance.&lt;/p&gt;
&lt;h2 id="want-to-learn-more"&gt;Want to Learn More?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Read Joe Sack&amp;rsquo;s &lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2017/04/19/introducing-interleaved-execution-for-multi-statement-table-valued-functions/"&gt;detailed post on Interleaved Execution for Multi-Statement TVFs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check out Joe&amp;rsquo;s &lt;a href="https://github.com/joesackmsft/Conferences/blob/master/Data_AMP_Detroit_2017/Demos/AQP_Demo_ReadMe.md"&gt;Adaptive Query Processing demos on GitHub&lt;/a&gt;, if you want to get your hands dirty in a test environment&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Remembering Robert Davis, aka @SQLSoldier</title><link>https://kendralittle.com/2018/04/03/remembering-robert-davis-aka-sqlsoldier/</link><pubDate>Tue, 03 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/03/remembering-robert-davis-aka-sqlsoldier/</guid><description>&lt;p&gt;I woke up early on Tuesday with a hundred things to do and plenty of energy to match my task list. By noon, I&amp;rsquo;d made a loaf of bread, helped a friend solve a tech mystery, and had various professional adventures.&lt;/p&gt;
&lt;p&gt;Then I opened Twitter and saw the news that Robert Davis passed away.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t really gotten much done in the hours since, except think about Robert. And cry a bit. And laugh. It feels weird laughing, but I think Robert would understand.&lt;/p&gt;
&lt;h2 id="robert-was-one-of-the-smartest-people-ill-ever-meet"&gt;Robert Was One of the Smartest People I&amp;rsquo;ll Ever Meet&lt;/h2&gt;
&lt;p&gt;Robert&amp;rsquo;s mind, and his memory, were amazing. He learned quickly and he had amazing recall of facts, he was so accurate and &lt;em&gt;fast&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Robert was someone who really knew it all, when it came to SQL Server - but he was the opposite of a know-it-all. He loved learning things, and he was always excited to find out how things worked and to share it. He didn&amp;rsquo;t hoard knowledge, he amplified it. Working with him always felt like collaboration, not competition.&lt;/p&gt;
&lt;p&gt;Robert was that rare funny person who made jokes without malice. He had a super quick wit, and he could make a sharp joke about politics, but he was a very kind and ethical person.&lt;/p&gt;
&lt;h2 id="robert-loved-helping-people-more-than-he-loved-being-right"&gt;Robert Loved Helping People More Than He Loved Being Right&lt;/h2&gt;
&lt;p&gt;I hadn&amp;rsquo;t thought about how special that is as a quality before today.&lt;/p&gt;
&lt;p&gt;Robert helped everyone on the internet. His help didn&amp;rsquo;t show any bias: if someone had a question and he could help, he&amp;rsquo;d try his best. If someone had information he didn&amp;rsquo;t, he welcomed it. If he learned something, he embraced it.&lt;/p&gt;
&lt;p&gt;Before I ever met Robert in person or saw him on Twitter, I knew him as that person at Microsoft who helped everyone on the internal distribution list. And this wasn&amp;rsquo;t just based on the power of his memory: Robert took the time to explain things. He took the time to help, even when there was nothing in it for him.&lt;/p&gt;
&lt;h2 id="robert-loved-stories-and-dogs"&gt;Robert Loved Stories and Dogs&lt;/h2&gt;
&lt;p&gt;Robert was great at describing things. I loved this description of his dog, Woody:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/SQLSoldier/status/960552770255380482"&gt;https://twitter.com/SQLSoldier/status/960552770255380482&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know what happens to us after we pass, and I know that Robert was an atheist, but I still find myself hoping that Robert and Woody are together again in some way.&lt;/p&gt;
&lt;p&gt;And I think if Robert knew that my own dog managed to poop on the floor right behind me while I was attempting to write this post, right when I couldn&amp;rsquo;t figure out how to turn off caps lock SO THAT EVERYTHING LOOKED LIKE YELLING &amp;ndash; I think he&amp;rsquo;d get a laugh out of that, too.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll miss you, Robert. I wish I&amp;rsquo;d told you how much I respected and admired you before you passed.&lt;/p&gt;
&lt;h2 id="keep-roberts-new-years-resolutions-for-him"&gt;Keep Robert&amp;rsquo;s New Year&amp;rsquo;s Resolutions for Him&lt;/h2&gt;
&lt;p&gt;Three months ago, Robert &lt;a href="http://sqlsoldier.net/wp/sqlserver/newyearsresolutionsforthisdba"&gt;wrote that he had three goals&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Spend less time working.&lt;/p&gt;
&lt;p&gt;Spend more time with my wife and our dog.&lt;/p&gt;
&lt;p&gt;Get out and do more things.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Robert can&amp;rsquo;t keep working on those goals, but &lt;em&gt;we&lt;/em&gt; can work on them in his honor.&lt;/p&gt;
&lt;h2 id="we-can-also-help-roberts-family"&gt;We Can Also Help Robert&amp;rsquo;s Family&lt;/h2&gt;
&lt;p&gt;Robert and his family were in the process of a cross-country move when he passed away. Please consider &lt;a href="https://www.gofundme.com/memorial-and-grief-fund-for-chrissy"&gt;helping his family&lt;/a&gt; if you are able.&lt;/p&gt;</description></item><item><title>Sys.dm_db_tuning_recommendations Makes Suggestions if Automatic Tuning is Not Enabled</title><link>https://kendralittle.com/2018/04/02/sys-dm_db_tuning_recommendations-makes-suggestions-if-automatic-tuning-isnt-enabled/</link><pubDate>Mon, 02 Apr 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/04/02/sys-dm_db_tuning_recommendations-makes-suggestions-if-automatic-tuning-isnt-enabled/</guid><description>&lt;p&gt;I naturally think about the new sys.dm_db_tuning_recommendations DMV when I&amp;rsquo;m working with the new Automatic Tuning feature in SQL Server 2017.&lt;/p&gt;
&lt;p&gt;But I came across &lt;a href="https://www.scarydba.com/2017/12/26/sql-server-automatic-tuning-and-sys-dm_db_tuning_recommendations/"&gt;a post by Grant Fritchey recently&lt;/a&gt;, in which he remarked in the conclusion&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt; Even if you don’t use [Automatic Tuning], you can take advantage of the information in sys.dm_db_tuning_recommendations as a starting point for adjusting your own plans.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;WHAAAAAAT?&lt;/p&gt;
&lt;p&gt;I had assumed that recommendations would only show up in  sys.dm_db_tuning_recommendations if I&amp;rsquo;d enabled automatic tuning for the database. I hadn&amp;rsquo;t even thought to test looking at the DMV if Query Store was set up but Automatic Tuning was disabled.&lt;/p&gt;
&lt;h2 id="what-does-the-recommendation-look-like-if-tuning-is-disabled"&gt;What Does the Recommendation Look Like if Tuning Is Disabled?&lt;/h2&gt;
&lt;p&gt;I had to know, so off to my test database! I did a fresh restore of my database, configured and enabled Query Store, and then made sure that automatic tuning was off:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CURRENT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTOMATIC_TUNING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FORCE_LAST_GOOD_PLAN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I verified that at this point,  sys.dm_db_tuning_recommendations didn&amp;rsquo;t have any rows.&lt;/p&gt;
&lt;p&gt;Then I ran a workload where a query gets a &amp;ldquo;faster&amp;rdquo; plan that executes 102 times, suffers a recompile (whoops!) and then runs again with a &amp;ldquo;slow&amp;rdquo; plan that executes another 102 times.&lt;/p&gt;
&lt;h2 id="sure-enough-i-got-a-recommendation"&gt;Sure Enough, I Got a Recommendation&lt;/h2&gt;
&lt;p&gt;Even though automatic tuning wasn&amp;rsquo;t enabled, SQL Server picked up on the performance changes. I got a recommendation in sys.dm_db_tuning_recommendations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reason: Average query CPU time changed from 2127.84ms to 66291.9ms&lt;/li&gt;
&lt;li&gt;state: {&amp;ldquo;currentValue&amp;rdquo;:&amp;ldquo;Active&amp;rdquo;,&amp;ldquo;reason&amp;rdquo;:&amp;ldquo;AutomaticTuningOptionNotEnabled&amp;rdquo;}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The details also include the query id in question, and the plan_id of the &amp;ldquo;fast plan&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="do-the-suggestions-show-up-in-standard-edition"&gt;Do the Suggestions Show Up in Standard Edition?&lt;/h2&gt;
&lt;p&gt;Automatic Tuning is an Enterprise Edition feature in SQL Server.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re like me, your next question was whether suggestions might appear in Standard Edition, even if you can&amp;rsquo;t formally enable Automatic Tuning.&lt;/p&gt;
&lt;p&gt;On my Standard Edition test instance, I can query sys.dm_db_tuning_recommendations, but no suggestions appear when I run my sample workload.&lt;/p&gt;
&lt;h2 id="heres-the-workaround-for-standard-edition"&gt;Here&amp;rsquo;s the Workaround for Standard Edition&lt;/h2&gt;
&lt;p&gt;Don&amp;rsquo;t worry, Query Store still has your back, you just have to find your own suggestions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open the new &amp;lsquo;Queries with High Variation&amp;rsquo; built in report&lt;/li&gt;
&lt;li&gt;Set the graph to Metric: CPU Time (ms), Based on Std Dev&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My problem query pops right to the top of the list with its fast and slow plans right in the graph.&lt;/p&gt;
&lt;p&gt;This does &lt;em&gt;not&lt;/em&gt; suck!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/standard-edition-workaround.png"&gt;
&lt;/figure&gt;
&lt;h2 id="it-turns-out-i-really-should-have-already-known-this"&gt;It Turns Out I Really Should Have Already Known This&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Erin Stellato mentioned this in &lt;a href="https://youtu.be/r3k3mrnk-cQ"&gt;her excellent session on Query Store and Automatic Tuning with Dejan Krakovic at the SQL PASS Summit last year&lt;/a&gt;. It just didn&amp;rsquo;t sink in the first time I heard it!&lt;/p&gt;
&lt;h2 id="i-love-a-good-suggestion"&gt;I Love a Good Suggestion!&lt;/h2&gt;
&lt;p&gt;I agree with Grant: I think the automatic tuning suggestions are a great place to start.&lt;/p&gt;
&lt;p&gt;Even if you like to have the Automatic Tuning enabled, the fact that it&amp;rsquo;s adjusting plans for you should be a trigger to looking at the queries and finding a way to keep the plans from being so volatile and needing adjustment.&lt;/p&gt;
&lt;p&gt;One note: suggestions disappear when the instance is restarted or the database goes offline &amp;ndash; so if you&amp;rsquo;d like to keep &amp;rsquo;em, you need to query them out of sys.dm_db_tuning_recommendations and persist them somewhere yourself.&lt;/p&gt;</description></item><item><title>Auto-Tuning: Automatic Plan Correction is Cleared on Restart</title><link>https://kendralittle.com/2018/03/28/auto-tuning-automatic-plan-correction-is-cleared-on-restart/</link><pubDate>Wed, 28 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/28/auto-tuning-automatic-plan-correction-is-cleared-on-restart/</guid><description>&lt;p&gt;The new Enterprise Automatic Tuning feature in SQL Server 2017 may sound intimidating at first &amp;ndash; one question I get a lot lately is whether or not there&amp;rsquo;s a future for DBAs. Will Auto-Tune mean we don&amp;rsquo;t need any more human tuning?&lt;/p&gt;
&lt;p&gt;Well, not anytime super soon.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a big fan of the Automatic Plan Correction feature in SQL Server 2017, but it reminds me a bit of the missing index DMVs we got in SQL Server 2005: the suggestions are a fantastic indication of where you need to look and use your powerful human brain.&lt;/p&gt;
&lt;h2 id="automatic-plan-correction-is-temporary--and-thats-a-good-thing"&gt;Automatic Plan Correction Is Temporary &amp;ndash; and That&amp;rsquo;s a Good Thing&lt;/h2&gt;
&lt;p&gt;One of the things I love about this feature is that it wisely includes some caution.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve enabled automatic tuning and it finds what looks like a plan regression, it won&amp;rsquo;t just force a plan and forget about it.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say we have a query where the average CPU time with Plan A is 2 seconds, and the average CPU time for Plan B is 10 seconds. If Automatic Plan Correction kicks in, we go into a state where Plan A is being verified.&lt;/p&gt;
&lt;h2 id="trust-but-verify"&gt;Trust, but Verify&lt;/h2&gt;
&lt;p&gt;Is Plan A really always faster? It may be that after Plan A is being ever so gently forced (ok, that&amp;rsquo;s not gentle), the query is run with different parameters, that make Plan A skew horribly wrong, and our average CPU time goes to 12 seconds. SQL Server is looking for that.&lt;/p&gt;
&lt;h2 id="un-force-when-things-change"&gt;Un-Force When Things Change&lt;/h2&gt;
&lt;p&gt;Automatic Plan Correction is also pretty skittish when it comes to change.&lt;/p&gt;
&lt;p&gt;Change indexes on the table? Whoops, we better un-force everything in case there&amp;rsquo;s something that could be faster! Update statistics on the table? Same thing!&lt;/p&gt;
&lt;p&gt;And also&amp;hellip;&lt;/p&gt;
&lt;h2 id="automatic-plan-corrections-dont-persist-over-restarts"&gt;Automatic Plan Corrections Don&amp;rsquo;t Persist Over Restarts&lt;/h2&gt;
&lt;p&gt;I did a little demo of this, just to prove it to myself.&lt;/p&gt;
&lt;p&gt;I have an Automatic Plan Correction in verification state. Here&amp;rsquo;s a view of it in sys.dm_db_tuning_recommendations:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/auto-tuning-in-verification-mode-1.png"&gt;
&lt;/figure&gt;
&lt;p&gt;But then, I restart my SQL Server instance:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/reeeestart.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Once the instance comes back up, Automatic Plan correction is no longer in place.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a different view, after restart. Looking at Query Id 25 in the Queries with High Variation report, there are NO check boxes in those bubbles to the right. Nothing is being forced.&lt;/p&gt;
&lt;p&gt;Everything is also gone from view in the sys.dm_db_tuning_recommendations. That data isn&amp;rsquo;t persisted after restarts.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/no-correction-after-restart.png"&gt;
&lt;/figure&gt;
&lt;h2 id="the-good-news-we-dont-completely-start-from-scratch"&gt;The Good News: We Don&amp;rsquo;t Completely Start from Scratch&lt;/h2&gt;
&lt;p&gt;My Query Store still has data about past performance of the plan.&lt;/p&gt;
&lt;p&gt;After restart, if my query happens to compile with the &amp;ldquo;slow plan&amp;rdquo;, the fast plan can be identified from the history capture in Query Store before the restart.&lt;/p&gt;
&lt;p&gt;In other words, Automatic Plan Correction doesn&amp;rsquo;t only consider information since the last restart when making its suggestions. I tested, and just by repeatedly running the &amp;ldquo;slow plan&amp;rdquo; for Query Id 25, a recommendation popped up. Since I have automatic tuning enabled for this database, it was automatically applied.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/iiits-baaack.png"&gt;
&lt;/figure&gt;
&lt;h2 id="think-of-automatic-tuning-as-an-assistant-dba"&gt;Think of Automatic Tuning as an Assistant DBA&lt;/h2&gt;
&lt;p&gt;And it&amp;rsquo;s better than just a random assistant! It&amp;rsquo;s an assistant that can help point you in the direction of problems like bad parameter sniffing, which are really hard to track down.&lt;/p&gt;
&lt;p&gt;If your environment is so sensitive that you don&amp;rsquo;t trust your assistant to just go tuning things, that&amp;rsquo;s fine! You don&amp;rsquo;t have to enable Automatic Tuning, and you can still &lt;a href="https://kendralittle.com/2018/04/02/sys-dm_db_tuning_recommendations-makes-suggestions-if-automatic-tuning-isnt-enabled/"&gt;look at the suggestions manually&lt;/a&gt; (as long as you&amp;rsquo;ve got Enterprise Edition).&lt;/p&gt;
&lt;p&gt;But at this point, and for the foreseeable future, your assistant still needs you to dig into the code, indexes, and architecture to find a better long term solution than just freezing the plan. Because if just freezing the plan was enough, this feature would be a whole lot simpler.&lt;/p&gt;</description></item><item><title>Partitioned Tables: Rolling/Rotating/Round-Robining Partitions</title><link>https://kendralittle.com/2018/03/26/partitioned-tables-rolling-rotating-round-robining-partitions/</link><pubDate>Mon, 26 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/26/partitioned-tables-rolling-rotating-round-robining-partitions/</guid><description>&lt;p&gt;I recently received a terrific question about options for &amp;ldquo;rotating&amp;rdquo; table partitions.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Rotating-Log-in-a-Forest.jpg"
alt="Rotating log pattern" width="230"&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m writing up a proposal for my company to start partitioning a 2.5TB table. The idea/need is to control the size of the table while saving the old data. The old data will be moved to an archive database on a different server where the BI guys work with it.&lt;/p&gt;
&lt;p&gt;In none of the videos articles I&amp;rsquo;ve seen is the explanation of how the rolling partition works on a long term daily basis.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Are the partitions reused, like in a ROUND ROBIN fashion?&lt;/li&gt;
&lt;li&gt;Or, do you add new partitions each day with new filegroups, drop the oldest partition off - this would be FIFO?&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lots of folks assume the answer here is always #2, simply because there&amp;rsquo;s a bunch of sample code out there for it.&lt;/p&gt;
&lt;p&gt;But option #1 can be simpler to manage when it fits your data retention technique!&lt;/p&gt;
&lt;h2 id="reusing-partitions---the-rotating-log-model"&gt;Reusing Partitions - the &amp;ldquo;Rotating Log&amp;rdquo; Model&lt;/h2&gt;
&lt;p&gt;Reusing partitions can absolutely work if you have a fixed number of partitions.&lt;/p&gt;
&lt;p&gt;By reusing partitions, you don&amp;rsquo;t need to manage the code or the locking required with splitting or merging your partition functions.&lt;/p&gt;
&lt;p&gt;You can still leverage switching, however.&lt;/p&gt;
&lt;p&gt;As long as you know that data in a given partition doesn&amp;rsquo;t need to be read, you can switch the data out and switch new data into it. You can also &lt;a href="https://blogs.msdn.microsoft.com/sqlcat/2016/08/11/sqlsweet16-episode-5-truncate-selected-partitions/"&gt;truncate individual partitions&lt;/a&gt; as of SQL Server 2016. (That is, of course, going to require high level locks.)&lt;/p&gt;
&lt;p&gt;This also means that you don&amp;rsquo;t have to constantly drop and recreate staging tables for switching data in, if you don&amp;rsquo;t want to.&lt;/p&gt;
&lt;p&gt;Thomas Kejser writes more about the rotating log pattern here: &lt;a href="http://kejser.org/table-pattern-rotating-log-ring-buffer/"&gt;http://kejser.org/table-pattern-rotating-log-ring-buffer/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="what-if-i-dont-have-a-fixed-number-of-partitions"&gt;What If I Don&amp;rsquo;t Have a Fixed Number of Partitions?&lt;/h2&gt;
&lt;p&gt;In Thomas&amp;rsquo; model, the data which is switched out will be used to update an aggregate table of older data.&lt;/p&gt;
&lt;p&gt;If you need to keep detail of older data, you could switch the data from the oldest partition into another table which is prepared as an archive table. You can even used indexed views to access data from both the &amp;ldquo;active&amp;rdquo; rolling table and the archive table together.&lt;/p&gt;
&lt;p&gt;Remember that switching is only allowed when partitions are on the same filegroup, so you would want to plan this carefully if that was the case.&lt;/p&gt;
&lt;p&gt;In the case of our questioner, older data will be moved out to another database, so it could simply be BCP&amp;rsquo;d out.&lt;/p&gt;
&lt;h2 id="one-note-about-filegroups"&gt;One Note About Filegroups&lt;/h2&gt;
&lt;p&gt;This question somewhat implies that each partition will be on its own filegroup.&lt;/p&gt;
&lt;p&gt;Sometimes folks use way more file groups than they need with the sliding window model, and it added extra complexity to their project.&lt;/p&gt;
&lt;p&gt;Filegroups can be very useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Individual restore sequences&lt;/li&gt;
&lt;li&gt;Running CHECKDB on part of the partitioned table with &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-checkfilegroup-transact-sql"&gt;DBCC CHECKFILEGROUP&lt;/a&gt; (there is no partition level checkdb)&lt;/li&gt;
&lt;li&gt;Putting some data on slower storage and some data on faster storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, if you are planning a very granular partition scheme, having one partition per filegroup can lead to a lot of wasted space if you ever rebuild data in each partition. It&amp;rsquo;s worth thinking about if it makes sense to &lt;em&gt;group&lt;/em&gt; multiple partitions on the same filegroups.&lt;/p&gt;</description></item><item><title>Why Is My Function Missing From sys.dm_exec_query_stats and Query Store?</title><link>https://kendralittle.com/2018/03/21/why-isnt-my-function-in-the-sys-dm_exec_query_stats-dynamic-management-view-and-in-query-store/</link><pubDate>Wed, 21 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/21/why-isnt-my-function-in-the-sys-dm_exec_query_stats-dynamic-management-view-and-in-query-store/</guid><description>&lt;p&gt;I just spent 90 minutes of my life figuring out a detail about &lt;strong&gt;sys.dm_exec_query_stats&lt;/strong&gt; which I’m pretty sure I figured out five years ago, but didn’t write a blog post about.&lt;/p&gt;
&lt;p&gt;Time to write a blog post, so I can save time when I go searching for this in a couple years.&lt;/p&gt;
&lt;h2 id="functions-can-be-tricksy-in-sql-server"&gt;Functions Can Be Tricksy in SQL Server&lt;/h2&gt;
&lt;p&gt;It can be difficult to see functions in execution plans, and to figure out when they&amp;rsquo;re eating a lot of CPU time on your SQL Server.&lt;/p&gt;
&lt;p&gt;One way that&amp;rsquo;s handy to see if functions are being executed frequently is to check out the &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-stats-transact-sql"&gt;sys.dm_exec_query_stats&lt;/a&gt; Dynamic Management View and look at the execution count, CPU time, and logical reads of the &amp;lsquo;CREATE FUNCTION&amp;rsquo; statement for a given function, to estimate its impact.&lt;/p&gt;
&lt;p&gt;But recently, I was working on a project and&amp;hellip;&lt;/p&gt;
&lt;p&gt;I couldn&amp;rsquo;t find my functions in sys.dm_exec_query_stats! I also couldn&amp;rsquo;t find them in Query Store.&lt;/p&gt;
&lt;h2 id="or-rather-i-couldnt-find-some-of-my-functions"&gt;Or, Rather, I Couldn&amp;rsquo;t Find SOME of My Functions&lt;/h2&gt;
&lt;p&gt;Some of my functions in the demo code were showing up just fine. I was really puzzled by that. I thought &amp;hellip;&lt;/p&gt;
&lt;p&gt;Maybe this is a bug with &amp;lsquo;CREATE OR ALTER&amp;rsquo;? A sign of some weird memory pressure? Something introduced in SQL Server 2017? A buggy side effect of implicit conversions in some of the functions? A problem with the queries I was using? A weird setting on the database? (Also: about 100 other things that didn&amp;rsquo;t turn out to be the case.)&lt;/p&gt;
&lt;p&gt;I finally wrote up &lt;a href="https://gist.github.com/LitKnd/16d28dcb8a82ae0eeda33e1667478b6d"&gt;some simple demo code&lt;/a&gt;, tested it against a SQL Server 2008 R2 instance (omitting the Query Store components), compared it with SQL Server 2017, and found it to be consistent.&lt;/p&gt;
&lt;p&gt;Some functions just don&amp;rsquo;t accrue information in sys.dm_exec_query_stats, and that&amp;rsquo;s been true for quite a while.&lt;/p&gt;
&lt;p&gt;I tested six types of functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scalar functions that do, and do not do data access&lt;/li&gt;
&lt;li&gt;Multi-statement table valued functions that do, and do not do data access&lt;/li&gt;
&lt;li&gt;Single statement table valued functions that do, and do not do data access&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="which-of-these-functions-appear-in-sysdm_exec_query_stats-and-sysquery_store_query"&gt;Which of These Functions Appear in sys.dm_exec_query_stats and sys.query_store_query?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Is-it-a-query.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;To be clear, the queries run which &lt;em&gt;call&lt;/em&gt; the functions all appear in sys.dm_exec_query_stats and sys.query_store_query. There are no missing calling queries.&lt;/p&gt;
&lt;p&gt;However, the calling query only shows things like how many times it was executed. It doesn&amp;rsquo;t show how many times the &lt;em&gt;function&lt;/em&gt; was executed (the function may be executed many times per query). Sometimes that&amp;rsquo;s handy to see when you&amp;rsquo;re troubleshooting.&lt;/p&gt;
&lt;p&gt;CREATE FUNCTION entries with per-function-execution data only appeared for my:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scalar function that does data access&lt;/li&gt;
&lt;li&gt;Multi-statement table valued function that does data access&lt;/li&gt;
&lt;li&gt;Multi-statement table valued function that does NOT do data access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It makes sense to me that my single statement table valued functions are missing from the list, because those functions can be &amp;ldquo;inlined&amp;rdquo; into their outer queries. They don&amp;rsquo;t really run on their own.&lt;/p&gt;
&lt;p&gt;However, it is a bit confusing that the scalar function that does not do data access is missing from the list. (I don&amp;rsquo;t think it&amp;rsquo;s a huge tragedy, but it makes it look like you&amp;rsquo;re missing something &amp;ndash; hence me spending a while on this!)&lt;/p&gt;
&lt;h2 id="which-of-these-functions-appear-in-sysdm_exec_function_stats"&gt;Which of These Functions Appear in sys.dm_exec_function_stats?&lt;/h2&gt;
&lt;p&gt;We got &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-function-stats-transact-sql"&gt;sys.dm_exec_function_stats&lt;/a&gt; in SQL Server 2016, so you can&amp;rsquo;t use this on Ye Older SQL Instances. This view recorded information for my:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scalar function that does data access&lt;/li&gt;
&lt;li&gt;Scalar function that does NOT do data access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why no table valued functions? This one is documented! The DMV simply doesn&amp;rsquo;t have information about Table Valued Functions.&lt;/p&gt;
&lt;h2 id="what-does-this-all-mean"&gt;What Does This All Mean?&lt;/h2&gt;
&lt;p&gt;If you have a lot of scalar functions that don&amp;rsquo;t do data access, and you&amp;rsquo;re on SQL Server 2016 and higher, check out &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-function-stats-transact-sql"&gt;sys.dm_exec_function_stats&lt;/a&gt;  for aggregate information on how they are running.&lt;/p&gt;
&lt;p&gt;And if you&amp;rsquo;re just confused about why not all your functions are showing up in sys.dm_exec_query_stats or Query Store, hopefully this post saves you some time!&lt;/p&gt;</description></item><item><title>Adding a Downloadable Calendar Event File to Wordpress without a Plugin</title><link>https://kendralittle.com/2018/03/19/adding-a-downloadable-calendar-event-file-to-wordpress-without-a-plugin/</link><pubDate>Mon, 19 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/19/adding-a-downloadable-calendar-event-file-to-wordpress-without-a-plugin/</guid><description>&lt;p&gt;Let&amp;rsquo;s say you&amp;rsquo;ll be doing an event soon &amp;ndash; say a Facebook Live event&amp;ndash; and you want to create a calendar reminder for folks to download. Lots of us live and die by calendar invites, so this can be helpful to get people to attend.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/calendar-disaster.jpg" width="230"&gt;
&lt;/figure&gt;
It seems like it&amp;rsquo;d be an easy enough thing to generate a file for this invitation and embed it on a Wordpress page, but I managed to mess this up six ways to Sunday recently.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I goofed up, and how I got it working.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: if you want to skip the long story, there's a recap of the steps that work at the end of the post.
&lt;/div&gt;
&lt;h2 id="generating-an-invitation-file---what-not-to-do-on-a-mac"&gt;Generating an Invitation File - What Not to Do on a Mac&lt;/h2&gt;
&lt;p&gt;I use a mac, so my first attempt was to generate the file using iCal, aka Calendar.app.&lt;/p&gt;
&lt;p&gt;I created the event, and then right clicked, and I didn&amp;rsquo;t see an &amp;lsquo;Export&amp;rsquo; option. So I went looking up in the &amp;lsquo;File&amp;rsquo; menu and found an &amp;lsquo;Export&amp;rsquo; option. &lt;strong&gt;&lt;em&gt;DON&amp;rsquo;T USE THAT!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I thought that would export the event I had selected. Nope, that exports the ENTIRE CALENDAR you&amp;rsquo;re on. And if you&amp;rsquo;re me, that means that after you test this file yourself, and it looks normal, you then ask others for a quick test on Twitter and find that you&amp;rsquo;ve shared events such as &amp;ldquo;Meatloaf Eating and Motorcycle Racing”, &amp;ldquo;Kendra eye surgery with Jeremiah as magnificent chauffeur&amp;rdquo;, and &amp;ldquo;Paws Cut Off&amp;rdquo; along with your intended event.&lt;/p&gt;
&lt;p&gt;And by the way: my dogs have all their paws, one of them is just a real drama queen every time he gets his nails clipped.&lt;/p&gt;
&lt;p&gt;Luckily, I don&amp;rsquo;t use that calendar for business, so it was only chunks of my personal life that I exposed. While we&amp;rsquo;re being open, I&amp;rsquo;m going to also share with you, dear reader, that I find botox very effective at temporarily removing forehead creases. Everyone may as well know.&lt;/p&gt;
&lt;p&gt;After quickly deleting that file and clearing every single cache I could find related to my webserver, I tried again! After all, I probably wasn&amp;rsquo;t going to make this worse.&lt;/p&gt;
&lt;h2 id="generating-an-invitation-file---a-better-attempt-on-a-mac-but-still-not-great"&gt;Generating an Invitation File - a Better Attempt on a Mac, but Still Not Great&lt;/h2&gt;
&lt;p&gt;This time, I right clicked on the event in iCal, selected “Mail Event”, then saved the attachment from the email.&lt;/p&gt;
&lt;p&gt;I also added the extra step of going to the saved .ics file and opening it in a text editor to verify that it contained only a single event, and not my entire personal life (or lack thereof). WHEW, it only had the one event. (I highly recommend this step!)&lt;/p&gt;
&lt;p&gt;But I found this still wasn&amp;rsquo;t perfect. It worked well on iOS, but my friend &lt;a href="https://twitter.com/way0utwest"&gt;Steve Jones&lt;/a&gt; found that this didn&amp;rsquo;t open as an invite for him on Outlook 2016, but instead popped up a separate calendar under my email address which he could add as a calendar.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t want a calendar, I wanted an invite!&lt;/p&gt;
&lt;h2 id="what-worked-generating-the-invitation-file-from-my-o365-account"&gt;What Worked: Generating the Invitation File from My O365 Account&lt;/h2&gt;
&lt;p&gt;I am lucky enough to have a free O365 account as part of my MVP benefit from Microsoft. &lt;a href="https://twitter.com/jdanton"&gt;Joey D&amp;rsquo;Antoni&lt;/a&gt; reminded me of that, so I logged in there and opened the calendar app.&lt;/p&gt;
&lt;p&gt;I set up an event in that calendar, but couldn&amp;rsquo;t find any &amp;ldquo;export&amp;rdquo; or &amp;ldquo;save event file&amp;rdquo; on the online GUI. So I right clicked it, selected &amp;ldquo;Forward&amp;rdquo;, and sent it to my work Gmail account.&lt;/p&gt;
&lt;p&gt;Once I got the email, it had a nice .ics file attached. I saved that file, edited it with a text editor and made the MAILTO address in it my work email address (my O365 email address is something hilariously weird), saved it, and tried that file.&lt;/p&gt;
&lt;p&gt;This .ics file opened properly as an invitation (not a separate calendar) even in Outlook 2016.&lt;/p&gt;
&lt;p&gt;I have not tested, but believe this would also work with a free account at Outlook.Live.com (the artist formerly known as Hotmail).&lt;/p&gt;
&lt;h2 id="theres-still-one-weird-thing-left-uploading-the-ics-file-to-wordpress"&gt;There&amp;rsquo;s Still One Weird Thing Left! Uploading the .ics File to WordPress&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve saved one little gem for last. When you are using the Media Library in wordpress to add new files, if you click the &amp;lsquo;Add New&amp;rsquo; button and then browse to your file, the .ics file will appear grayed out and you cannot select it for upload.&lt;/p&gt;
&lt;p&gt;It looks like you just can&amp;rsquo;t do it.&lt;/p&gt;
&lt;p&gt;But, if you simply &lt;em&gt;drag&lt;/em&gt; the .ics file over into the media library, it uploads fine!&lt;/p&gt;
&lt;p&gt;Just don&amp;rsquo;t use the &amp;lsquo;Add new&amp;rsquo; dialog.&lt;/p&gt;
&lt;p&gt;No. Idea. Why. I&amp;rsquo;m just going with it.&lt;/p&gt;
&lt;h2 id="recap-my-process-for-generating-and-uploading-calendar--event-reminder-files-to-wordpress"&gt;Recap: My Process for Generating and Uploading Calendar / Event Reminder Files to WordPress&lt;/h2&gt;
&lt;p&gt;The next time I have to do this, I&amp;rsquo;ll have forgotten all of this. So here&amp;rsquo;s my cheat sheet for myself (and hopefully for some strangers on the internet who need this):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create an event in O365 (or another Outlook friendly app, such as Outlook.Live.com) for your event. Make sure you have the duration correct, etc.&lt;/li&gt;
&lt;li&gt;Right click, select &amp;lsquo;Forward&amp;rsquo;, and send it to a different account (I used my gmail account).&lt;/li&gt;
&lt;li&gt;Open the email. It will have a .ics file as an attachment. Save this file.&lt;/li&gt;
&lt;li&gt;Right click on the .ics file and open it with your favorite text editor. Find the MAILTO: email address and change it to your preferred email, if desired. Save the file&lt;/li&gt;
&lt;li&gt;Upload the file to Wordpress by dragging the file into the Media Library (the &amp;lsquo;Add New&amp;rsquo; dialog doesn&amp;rsquo;t like .ics extensions, but this works for now at least)&lt;/li&gt;
&lt;li&gt;Copy the link off the uploaded file and use it in posts/pages/etc.&lt;/li&gt;
&lt;li&gt;Profit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is probably an easier way to do this if you use &amp;lsquo;real&amp;rsquo; Outlook, but that ship sailed for me years ago. (Nothing personal, Outlook, I hear a lot of people love you.)&lt;/p&gt;</description></item><item><title>New Course: Why Table Partitioning Does Not Speed Up Query Performance – With One Exception</title><link>https://kendralittle.com/2018/03/15/new-course-why-table-partitioning-does-not-speed-up-query-performance-with-one-exception/</link><pubDate>Thu, 15 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/15/new-course-why-table-partitioning-does-not-speed-up-query-performance-with-one-exception/</guid><description>&lt;h2 id="table-partitioning-is-tricky-business"&gt;Table Partitioning is Tricky Business&lt;/h2&gt;
&lt;p&gt;In this &lt;a href="https://kendralittle.com/course/why-table-partitioning-does-not-speed-up-query-performance-with-exception/"&gt;new course&lt;/a&gt; you will learn why SQL Server’s table partitioning feature won’t make your queries against disk-based rowstore indexes faster– and may even make them slower.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Why-Table-Partitioning-Doesnt-Speed-Up-Queries-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
Table partitioning can absolutely be worth implementing, but it may be for different reasons than you think!&lt;/p&gt;
&lt;p&gt;In this course, you will learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What partition elimination really does&lt;/li&gt;
&lt;li&gt;Why table partitioning makes some queries trickier to optimize&lt;/li&gt;
&lt;li&gt;Where table partitioning shines – and in which case it &lt;em&gt;can&lt;/em&gt; make queries faster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The videos in this session include selected questions and answers with a live audience. In these videos, I use diagrams to visually explain the concepts involved.&lt;/p&gt;
&lt;h2 id="like-to-get-your-hands-on-code-to-learn"&gt;Like to Get Your Hands on Code to Learn?&lt;/h2&gt;
&lt;p&gt;Yeah, me too. Course downloads include scripts that quickly create, populate, and explore the example table we walk through in the course, so you can prove each concept explained in the course.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/course/why-table-partitioning-does-not-speed-up-query-performance-with-exception/"&gt;This course is now freely availabile to everyone&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>The Case of MAX() Requiring an Index Scan, While TOP(1)/ORDER BY DESC Does Not</title><link>https://kendralittle.com/2018/03/14/the-case-of-max-requiring-an-index-scan-while-top1-order-by-desc-does-not/</link><pubDate>Wed, 14 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/14/the-case-of-max-requiring-an-index-scan-while-top1-order-by-desc-does-not/</guid><description>&lt;p&gt;Most of the time in SQL Server, the MAX() function and a TOP(1) ORDER BY DESC will behave very similarly.&lt;/p&gt;
&lt;p&gt;If you give them a rowstore index leading on the column in question, they&amp;rsquo;re generally smart enough to go to the correct end of the index, and &amp;ndash; BOOP! &amp;ndash; just pluck out the data you need without doing a big scan.&lt;/p&gt;
&lt;p&gt;I got an email recently about a case when SQL Server was not smart enough to do this with MAX() &amp;ndash; but it was doing just fine with a TOP(1) ORDER BY DESC combo.&lt;/p&gt;
&lt;p&gt;The question was: what&amp;rsquo;s the problem with this MAX?&lt;/p&gt;
&lt;p&gt;It took me a while to figure it out, but I finally got to the bottom of the case of the slow MAX.&lt;/p&gt;
&lt;h2 id="i-got-the-problem-in-the-form-of-a-database-backup"&gt;I Got the Problem in the Form of a Database Backup&lt;/h2&gt;
&lt;p&gt;Dear readers, it is not &lt;em&gt;always&lt;/em&gt; a good idea restore database backups from strangers on the internet. People can put nasty things in there, just like any old thing you zip up and attach to an email.&lt;/p&gt;
&lt;p&gt;But this backup was from a fellow Microsoft MVP, I was curious about the problem, and I have a nice, isolated test instance in a VM just waiting to be tormented. So I went forth and restored!&lt;/p&gt;
&lt;p&gt;Sure enough, I could reproduce the issue.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what it looked like &amp;ndash; but in a fake table that I&amp;rsquo;ve created from scratch, which reproduces the issue.&lt;/p&gt;
&lt;h2 id="slow-query-vs-fast-query"&gt;Slow Query vs Fast Query&lt;/h2&gt;
&lt;h2 id="meet-slow-query"&gt;Meet Slow Query&lt;/h2&gt;
&lt;p&gt;Here is the actual plan for the problem query (view from Sentry One&amp;rsquo;s &lt;a href="https://www.sentryone.com/plan-explorer"&gt;free Plan Explorer&lt;/a&gt;)&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/slow-query-with-plan-no-top.png"&gt;
&lt;/figure&gt;
&lt;p&gt;That nonclustered index leads on CharColumn. SQL Server correctly estimated that there are 1 million rows in the index and it fed them all faithfully into a Stream Aggregate operator to do the MAX.&lt;/p&gt;
&lt;h2 id="meet-fast-query"&gt;Meet Fast Query&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/fast-query-with-top.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Fast query used the &lt;em&gt;very same&lt;/em&gt; index. It figured out that it could go to one end of the index and do a quick backward scan, feeding that TOP 1 row into a TOP operator and then stopping.&lt;/p&gt;
&lt;p&gt;And it was correct. One row read, not one million!&lt;/p&gt;
&lt;h2 id="a-few-metrics"&gt;A Few Metrics&lt;/h2&gt;
&lt;p&gt;SQL Server estimated that this MAX query was going to be more expensive than the TOP, and it was right:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/slow-plan-vs-fast-plan-comparison.png"&gt;
&lt;/figure&gt;
&lt;p&gt;These metrics are for the queries in a simple, narrow table with a single column nonclustered index on CharColumn. Add more rows and more complexity, and the performance difference will just get uglier.&lt;/p&gt;
&lt;h2 id="initial-observations"&gt;Initial Observations&lt;/h2&gt;
&lt;p&gt;The first thing I noticed is that we&amp;rsquo;re doing MAX against a CHAR column. CHAR is a fixed length, non-unicode data type.&lt;/p&gt;
&lt;p&gt;Actually, that&amp;rsquo;s not the first thing I noticed.&lt;/p&gt;
&lt;h2 id="the-first-thing-i-noticed-was-that-this-is-a-dynamics-database"&gt;The First Thing I Noticed Was That This Is a Dynamics Database&lt;/h2&gt;
&lt;p&gt;The kindly fellow who raised this question let me know right away that his question is regarding a Dynamics database. That was one of the initial things that forewarned me that things might get wacky.&lt;/p&gt;
&lt;p&gt;Having done some consulting for a while, I know the look that SQL Server specialists get when confronted with any database that&amp;rsquo;s a member of the Dynamics family.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQL-Server-DBA-Confronted-with-Dynamics-Database.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;It&amp;rsquo;s not that Dynamics is bad, it&amp;rsquo;s just &amp;hellip; weird. The kind of weird that can lead you to think that your database is haunted, because it gets unusual behaviors related to its strange habits. (Heaps, odd settings, strange creaks in the night&amp;hellip;)&lt;/p&gt;
&lt;p&gt;Strange things like this issue.&lt;/p&gt;
&lt;p&gt;But we can figure out EVEN A DYNAMICS query tuning problem, right? YES, WE CAN!&lt;/p&gt;
&lt;h2 id="you-can-use-max-against-a-character-column-and-this-doesnt-always-happen"&gt;You Can Use MAX() Against a Character Column, and This Doesn&amp;rsquo;t Always Happen&lt;/h2&gt;
&lt;p&gt;The very first thing I tested was whether or not this &amp;ldquo;scan all the rows and push them into a stream aggregate for MAX&amp;rdquo; issue happened against other CHAR columns.&lt;/p&gt;
&lt;p&gt;I selected CHAR data from another table in another database into a new table in my test database, indexed it, and started querying it.&lt;/p&gt;
&lt;p&gt;It worked fine - the MAX() plan estimated one row into a top operator, then fed that single row into a stream aggregate.&lt;/p&gt;
&lt;p&gt;I made the CHAR data into a CHAR(13) column, same as the test table.&lt;/p&gt;
&lt;p&gt;It worked fine, too.&lt;/p&gt;
&lt;h2 id="i-spun-my-wheels-for-a-while"&gt;I Spun My Wheels for a While&lt;/h2&gt;
&lt;p&gt;I spent about half an hour testing random things, that didn&amp;rsquo;t end up helping. Things like&amp;hellip;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Looking at the boot page of the database to see if there was any weird history of logs being rebuild that might cause this table to be funky. Nope.&lt;/li&gt;
&lt;li&gt;Creating a clustered index on the test table. (It was a heap.) No change in behavior.&lt;/li&gt;
&lt;li&gt;Changing the sort order of the nonclustered index on the test table. Nada, no change in behavior.&lt;/li&gt;
&lt;li&gt;Performing various rituals with random trace flags, then admitting this ritual was ridiculous.&lt;/li&gt;
&lt;li&gt;Asking my dog what he thought, and he thought it was time for dinner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sorry, dog, I have one last thing to test.&lt;/p&gt;
&lt;h2 id="i-altered-the-column-and-that-fixed-it"&gt;I Altered the Column, and That Fixed It&lt;/h2&gt;
&lt;p&gt;The problem CHAR column didn&amp;rsquo;t allow nulls. In the documentation for MAX, it mentioned that it skips NULL values. The column seemed perfectly attuned to that, but I thought, hey, maybe switch that on my test column and see what happens?&lt;/p&gt;
&lt;p&gt;So I ran this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserDatabaseTable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COLUMN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CharColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I didn&amp;rsquo;t change the column length, I just made it allow NULLs.&lt;/p&gt;
&lt;p&gt;After this, when I re-ran the MAX query, the plan looked like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/slow-plan-is-now-fast.png"&gt;
&lt;/figure&gt;
&lt;p&gt;This is what we wanted our MAX() query to do all along &amp;ndash; feed a row into a TOP operator. Yes, we still have a stream aggregate there, but it&amp;rsquo;s a lot faster when it&amp;rsquo;s only getting one row.&lt;/p&gt;
&lt;p&gt;This query took 0 seconds of CPU time and did 3 logical reads. It now matched the performance for the TOP(1) / ORDER BY query.&lt;/p&gt;
&lt;h2 id="but-wait-its-not-allowing-nulls-that-fixes-it"&gt;But Wait, It&amp;rsquo;s Not Allowing NULLs That Fixes It&lt;/h2&gt;
&lt;p&gt;I was making progress, but this was still really fishy. After all, MAX does not count NULL values, so if the column didn&amp;rsquo;t allow NULLs, that seems like it would make MAX&amp;rsquo;s job easier, not harder.&lt;/p&gt;
&lt;p&gt;So I wondered if it was just the act of altering the column that made the difference, not changing the NULL-ability.&lt;/p&gt;
&lt;p&gt;I re-restored the database, and I ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserDatabaseTable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COLUMN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CharColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yep, I altered the column to be JUST LIKE it already was.&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;also&lt;/em&gt; fixed the issue.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not the NULLs, it&amp;rsquo;s some side-effect of altering the column. I scratched my head, looked at the dog, and called it a night. Relaxation and sleep can be good for this kind of thing.&lt;/p&gt;
&lt;h2 id="sure-enough-it-all-made-sense-in-the-morning"&gt;Sure Enough, It All Made Sense in the Morning&lt;/h2&gt;
&lt;p&gt;In the morning, I played around with the table a bit more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Selecting data from the column into a new table in tempdb still had the scan problem / was slow&lt;/li&gt;
&lt;li&gt;Scripting out the table, creating it in tempdb, and inserting the data was fast every time - TOP operator was just fine!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This convinced me that it was nothing about that specific table or that specific database.&lt;/p&gt;
&lt;p&gt;This problem is a &lt;em&gt;column&lt;/em&gt; problem.&lt;/p&gt;
&lt;h2 id="i-started-looking-at-the-column-properties"&gt;I Started Looking at the Column Properties&lt;/h2&gt;
&lt;p&gt;I suspected I was close to the answer at this point, and I got all excited and happy. I could barely type sensible TSQL, but I managed to query sys.columns for the table when it had the problem, and after I fixed it with an ALTER:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_NAME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UserDatabaseTable&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;CharColumn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And I found the answer.&lt;/p&gt;
&lt;h2 id="ansi-padding-you-little-devil"&gt;ANSI PADDING, You Little Devil!&lt;/h2&gt;
&lt;p&gt;When this CHAR(13) column has is_ansi_padded set to 0 (false), the MAX() operation generates an index scan that feeds the data into a stream aggregate operator.&lt;/p&gt;
&lt;p&gt;The TOP(1) / ORDER BY combo doesn&amp;rsquo;t care.&lt;/p&gt;
&lt;p&gt;MY ALTER TABLE / ALTER COLUMN statements have the effect of setting is_ansi_padded to 1 (true), which is the setting SQL Server generally prefers. With ANSI_PADDING on for the column, SQL Server says, &amp;ldquo;oh, I don&amp;rsquo;t need to read every row!&amp;rdquo; and just goes to the end of the index.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: Running &lt;code&gt;SET ANSI_PADDING OFF;&lt;/code&gt; in my session to match my session settings to the column setting doesn't change anything. This is not a problem of session settings mis-matching the column settings, this is a problem with the ANSI_PADDING setting on the column itself.
&lt;/div&gt;
&lt;h2 id="what-in-the-world-is-ansi-padding"&gt;What in the World Is ANSI PADDING?&lt;/h2&gt;
&lt;p&gt;These ANSI settings are weird and esoteric. Here is a summary of ANSI PADDING from &amp;ldquo;&lt;a href="https://support.microsoft.com/en-us/help/316626/inf-how-sql-server-compares-strings-with-trailing-spaces"&gt;INF: How SQL Server Compares Strings with Trailing Spaces&lt;/a&gt;&amp;rdquo;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SQL Server follows the ANSI/ISO SQL-92 specification (Section 8.2, &lt;Comparison Predicate&gt;, General rules #3) on how to compare strings with spaces. The ANSI standard requires padding for the character strings used in comparisons so that their lengths match before comparing them. The padding directly affects the semantics of WHERE and HAVING clause predicates and other Transact-SQL string comparisons.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The article has more helpful info, so if you&amp;rsquo;re curious, go ahead and click through and read it.&lt;/p&gt;
&lt;h2 id="this-makes-sense-and-its-even-documented-mostly"&gt;This Makes Sense! And It&amp;rsquo;s Even Documented (Mostly)&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Ideas-with-keyboard-and-mouse-2.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;We&amp;rsquo;ve solved the mystery, as far as the MAX() query goes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ANSI spec SQL Server follows requires padding for CHAR columns when comparing them&lt;/li&gt;
&lt;li&gt;MAX() is comparing values, so it seems fair that it would have to scan every row in the index, pad them (since ansi padding is OFF for the column), then do the MAX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But&amp;hellip; what about the TOP (1) / ORDER BY query?&lt;/p&gt;
&lt;p&gt;Isn&amp;rsquo;t ORDER BY also comparing values?&lt;/p&gt;
&lt;p&gt;Shouldn&amp;rsquo;t that query &lt;em&gt;also&lt;/em&gt; have to look at every row, for the ORDER BY operation? If there&amp;rsquo;s a bug here, it seems kinda like the TOP (1) / ORDER BY query is the one who is misbehaving.&lt;/p&gt;
&lt;p&gt;I found a tiny piece of documentation for this (after I figured it out, of course - isn&amp;rsquo;t that always the way) in the Books Online article for &lt;a href="https://technet.microsoft.com/en-us/library/ms187403.aspx"&gt;SET ANSI_PADDING&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt; When ANSI_PADDING set to OFF, queries that involve MIN, MAX, or TOP on character columns might be slower than in SQL Server 2000.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It does seem from this that TOP/ORDER BY should be padding all the strings before comparing them, I&amp;rsquo;m pretty reluctant to file a feature request saying I think something should be slower (and for a deprecated setting).&lt;/p&gt;
&lt;p&gt;For most folks, the message is: before you create a table, it&amp;rsquo;s good to make sure you&amp;rsquo;re using the ANSI settings that SQL Server recommends. &lt;a href="https://technet.microsoft.com/en-us/library/ms175088.aspx"&gt;Here is a list in the Microsoft documentation&lt;/a&gt;. One of them is: SET ANSI_PADDING ON.&lt;/p&gt;
&lt;p&gt;In fact, in the case of this Dynamics database, our questioner started looking into this and found that setting ANSI_PADDING to off may no longer be required. WOOT!&lt;/p&gt;
&lt;p&gt;If you want to know if any of your existing tables has this problem, you can query sys.columns to find out (like in the query above).&lt;/p&gt;
&lt;h2 id="mystery-solved"&gt;Mystery Solved!&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to play around with code that reproduces the problem in this mystery, you can &lt;a href="https://gist.github.com/LitKnd/c7c28e4ab212815efff7334ebbfbfbf0"&gt;grab it here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>SQL Server 2026: BAGI Edition (#TSQL2SDAY 100!)</title><link>https://kendralittle.com/2018/03/13/sql-server-2026-bagi-edition-tsql2sday-100/</link><pubDate>Tue, 13 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/13/sql-server-2026-bagi-edition-tsql2sday-100/</guid><description>&lt;p&gt;It&amp;rsquo;s T-SQL Tuesday&amp;rsquo;s 8 year birthday (or close enough), and &lt;a href="https://twitter.com/AdamMachanic"&gt;Adam Machanic&lt;/a&gt; has challenged us with the question: what will the world be like when T-SQLTuesday turns 16?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tsql2sday-logo.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Not familiar with T-SQL Tuesday? It&amp;rsquo;s a monthly event where you&amp;rsquo;re invited to join in blogging on a given topic. Invitations are posted centrally &lt;a href="http://tsqltuesday.com"&gt;here&lt;/a&gt;, and &lt;a href="https://kendralittle.com/2017/08/21/how-to-get-email-notifications-for-tsqltuesday/"&gt;here&amp;rsquo;s how to set up emails&lt;/a&gt; if you&amp;rsquo;d like the invitation in your inbox.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="in-2026-sql-server-will-still-exist-but-times-will-have-changed"&gt;In 2026, SQL Server Will Still Exist, but Times Will Have Changed&lt;/h2&gt;
&lt;p&gt;Individual servers, virtual machines, instances, databases - many of us will still know those concepts well and fondly. But most new applications will be written for and deployed on BAGIs.&lt;/p&gt;
&lt;h2 id="the-big-bagi-big-awesome-giant-infrastructure"&gt;The Big BAGI: Big Awesome Giant Infrastructure&lt;/h2&gt;
&lt;p&gt;Big BAGIs will be giant compute clusters, run by a variety of providers. These compute clusters won&amp;rsquo;t have any tape storage, no spinning disks, not even any SSDs as we know them today. Instead, they&amp;rsquo;ll be loaded with vast amounts of specialized memory, which achieves high availability by super fast networking between compute clusters in different datacenters.&lt;/p&gt;
&lt;h2 id="little-bagis-live-on-the-big-bagi"&gt;Little BAGI&amp;rsquo;s Live on the Big BAGI&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/BAGIs.jpg" width="230"&gt;
&lt;/figure&gt;
Data will be stored not in databases, but in little BAGI&amp;rsquo;s: Bundles of All Generated Information.&lt;/p&gt;
&lt;p&gt;Your BAGI may contain relational data, document data, graph data, or many more different types of data. Your applications will be able to access BAGIs of different types, and manipulate and process that data using Daemons &amp;ndash; one of which is the SQL Server Daemon, whose binaries live on the Big BAGI. Different Big BAGI Daemons will have specialized optimization techniques and abilities to scale.&lt;/p&gt;
&lt;p&gt;When you create a little BAGI, it will always live on one more more Big BAGI, and your writes to your BAGI are always written to both, with automatic conflict resolution.&lt;/p&gt;
&lt;p&gt;How is the conflict resolution determined? You configure your BAGIs in groups, and each group of BAGIs has a data steward. On a contractual basis of your choosing, Cordelia (Cortana&amp;rsquo;s descendant), checks in with the data steward with a Q&amp;amp;A session on data retention, conflict resolution, and BAGI security, and cost management.&lt;/p&gt;
&lt;h2 id="whats-the-licensing-like"&gt;What&amp;rsquo;s the Licensing Like?&lt;/h2&gt;
&lt;p&gt;You have options. You can either pay by the gram &amp;ndash; literally, the weight that the data takes up in memory, multiplied by a fluctuating currency charge &amp;ndash; or if you want lower-latency data access, you can pay higher rates for bigger individual BAGIs, many BAGIs guaranteed to be in close proximity of one another, or a certain level of global redundancy of your BAGIs, having your BAGIs hosted on a minimum number of providers, etc.&lt;/p&gt;
&lt;h2 id="my-data-is-in-a-bagi-and-its-sold-by-the-gram"&gt;My Data Is in a BAGI and It&amp;rsquo;s Sold by the Gram?&lt;/h2&gt;
&lt;p&gt;Yes, data will have truly become our favorite cultural drug.&lt;/p&gt;</description></item><item><title>New Free Webinars! Index Tuning, Free Q&amp;A, and Isolation Levels</title><link>https://kendralittle.com/2018/03/12/new-free-webinars-index-tuning-free-qa-and-isolation-levels/</link><pubDate>Mon, 12 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/12/new-free-webinars-index-tuning-free-qa-and-isolation-levels/</guid><description>&lt;p&gt;I&amp;rsquo;ve got a whole slew of free webcasts and events coming this spring. I&amp;rsquo;m excited about each and every one of them!&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Grab-a-Seat-Detective-Scoots.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="idera-sponsored-event"&gt;IDERA Sponsored Event&lt;/h2&gt;
&lt;p&gt;My next event is a free session sponsored by IDERA software on index tuning. For this event, you register on IDERA&amp;rsquo;s site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mar 21 – Why Did My Clever Index Change Backfire? (Geek Sync with IDERA) &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="additional-webcasts-and-events"&gt;Additional Webcasts and Events&lt;/h2&gt;
&lt;p&gt;After that, I&amp;rsquo;ll be doing webcasts, plus a Q&amp;amp;A session with the Professional Association for SQL Server using Facebook Live.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mar 22 – Configuring MAXDOP&lt;/li&gt;
&lt;li&gt;Mar 27 – PASS Facebook Live Pop-Up Q&amp;amp;A Session&lt;/li&gt;
&lt;li&gt;Apr 5 – Configuring Cost Threshold&lt;/li&gt;
&lt;li&gt;Apr 26 – Snapshot Isolation on AG Secondaries&lt;/li&gt;
&lt;li&gt;May 10 – Read Committed is Bonkers (repeat showing)&lt;/li&gt;
&lt;li&gt;May 24 – RCSI &amp;amp; Snapshot Isolation (repeat showing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Registration for these events has now closed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hope to see you at these events!&lt;/p&gt;</description></item><item><title>What is a Morally Equivalent Execution Plan, and Why Is It Useful?</title><link>https://kendralittle.com/2018/03/12/what-is-a-morally-equivalent-execution-plan-and-why-is-it-good/</link><pubDate>Mon, 12 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/12/what-is-a-morally-equivalent-execution-plan-and-why-is-it-good/</guid><description>&lt;p&gt;I recently wrote a fairly complicated post, called &amp;ldquo;&lt;a href="https://kendralittle.com/2018/03/05/forced-plan-confusion-is_forced-vs-use-plan-true/"&gt;Forced Plan Confusion: Is_Forced vs Use Plan = True&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;You do NOT need to go read that post to understand this one. I think I&amp;rsquo;ve found simpler way to explain the most important part of that post - and why it&amp;rsquo;s &lt;em&gt;A Very Good Thing&lt;/em&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Wiggle-Room.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="plan-forcing-in-query-store-is-clever"&gt;Plan forcing in Query Store is clever&lt;/h2&gt;
&lt;p&gt;The gist of this post is that plan forcing in Query Store is not the same as just putting duct-tape on an execution plan.&lt;/p&gt;
&lt;p&gt;Query Store is a little more flexible than that. It has an understanding that if you force something too tightly, it may break.&lt;/p&gt;
&lt;p&gt;It leaves a little wiggle room. SQL Server may compile a &amp;ldquo;Morally Equivalent Plan&amp;rdquo; if a query plan has been forced, but the optimizer looks at the plan and the &amp;ldquo;compile for&amp;rdquo; values and sees that the query plan is the wrong size pants for that query.&lt;/p&gt;
&lt;h2 id="step-1-i-put-a-plan-in-query-store"&gt;Step 1: I put a plan in Query Store&lt;/h2&gt;
&lt;p&gt;To get this party started, I restore the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters&lt;/a&gt; sample database and enable Query Store. I run a query and get its plan into cache.&lt;/p&gt;
&lt;p&gt;The plan looks like this &amp;ndash; notice that @packagetypeid is parameterized&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/small-plan.png"&gt;
&lt;/figure&gt;
&lt;p&gt;This plan has an estimated cost of .0067516. It thinks &lt;em&gt;one row&lt;/em&gt; is going to flow through the whole query.&lt;/p&gt;
&lt;h2 id="step-2-i-force-that-plan"&gt;Step 2: I force that plan&lt;/h2&gt;
&lt;p&gt;I run a query against the Query Store DMVs to figure out the query_id and plan_id for this query.&lt;/p&gt;
&lt;p&gt;Then I force it by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That one-row plan you see above is now forced!&lt;/p&gt;
&lt;h2 id="step-3-i-cause-a-recompile-to-happen"&gt;Step 3: I cause a recompile to happen&lt;/h2&gt;
&lt;p&gt;The forced plan is currently in my execution plan cache. I want to cause a recompile to happen, so I clear out the cache for this database on my test instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCOPED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONFIGURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCEDURE_CACHE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next time my query runs, it&amp;rsquo;s going to get a fresh compile. Yes, it has a forced plan, but let&amp;rsquo;s see what happens.&lt;/p&gt;
&lt;h2 id="step-4-i-run-the-same-query-but-with-a-different-value-for-packagetypeid"&gt;Step 4: I run the same query, but with a different value for @packagetypeid&lt;/h2&gt;
&lt;p&gt;When SQL Server compiles my query, it doesn&amp;rsquo;t blindly give me the exact forced plan with its one row estimates.&lt;/p&gt;
&lt;p&gt;Instead, it sniffs the value of my parameters. It uses that sniffed value to look at the statistics. And it sees that I&amp;rsquo;m pretty likely to have more than one row flowing through this plan. Based on the statistics, it looks more like 221,241 rows!&lt;/p&gt;
&lt;p&gt;So, clever SQL Server gives me a &amp;ldquo;morally equivalent plan&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="meet-the-morally-equivalent-plan"&gt;Meet the &amp;ldquo;morally equivalent plan&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;Notice that this plan has the same shape as the plan above. That&amp;rsquo;s the &amp;ldquo;moral equivalency.&amp;rdquo; We&amp;rsquo;ve got our Seek -&amp;gt; Nested Loops -&amp;gt; Key Lookups. Compute Scalar feeds into Stream Aggregate, etc.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/the-morally-equivalent-plan.png"&gt;
&lt;/figure&gt;
&lt;p&gt;But there are some differences!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have thicker row estimate bars, based on that statistic that was sniffed&lt;/li&gt;
&lt;li&gt;My plan estimated subtree cost is 51.0062 (the forced plan is .0067516)&lt;/li&gt;
&lt;li&gt;My plan has a green hint that points out my indexing on OrderLines isn&amp;rsquo;t so great &amp;ndash; and my costs are different on my operators!
&lt;ul&gt;
&lt;li&gt;The Key Lookup is now estimated at 97% of the work, whereas before it was 50%&lt;/li&gt;
&lt;li&gt;SQL Server isn&amp;rsquo;t thrilled about doing that lookup 221,241 times. It was no big deal to just do it once, so there was no missing index request when this was optimized for a different parameter.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-morally-equivalent-plan-has-its-own-query_plan_id-query_plan_hash-and-shows-up-as-separate-in-query-store"&gt;The &amp;ldquo;morally equivalent plan&amp;rdquo; has its own query_plan_id, query_plan_hash, and shows up as separate in Query Store&lt;/h2&gt;
&lt;p&gt;Both the forced plan and the &amp;ldquo;morally equivalent&amp;rdquo; plan are visible in Query Store. It can be a little confusing to identify them if you haven&amp;rsquo;t seen them before.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The forced plan has is_forced = 1 in sys.query_store_plan and will have a check mark in the Query Store reports.&lt;/li&gt;
&lt;li&gt;The &amp;ldquo;morally equivalent plan&amp;rdquo; will have &amp;ldquo;Use Plan=true&amp;rdquo; in the properties of the left-most operator in the plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The good news: if you open the &amp;ldquo;Queries with forced plans&amp;rdquo; report, both of them show up there.&lt;/p&gt;
&lt;h2 id="same-shape-sized-to-fit-the-parameters-it-compiled-with"&gt;Same shape, sized to fit the parameters it compiled with&lt;/h2&gt;
&lt;p&gt;I think this &amp;ldquo;wiggle room&amp;rdquo; is a terrific feature for forced plans.&lt;/p&gt;
&lt;p&gt;Forcing plans is a somewhat crude thing to do &amp;ndash; just because a forced plan works better today, doesn&amp;rsquo;t mean that the forced plan is going to be great tomorrow, if a bunch of my data changes. Or if a different customer is running the procedure, one who has quite a different data profile.&lt;/p&gt;
&lt;p&gt;This feature is kind of like a stretchy waistband for the sweatpants of an execution plan. Maybe you need a bigger memory grant than the one forced with the original plan? Here&amp;rsquo;s a little wiggle room.&lt;/p&gt;
&lt;p&gt;Plus, if I happen to check up on my forced queries in Query Store, I can notice that often when this runs it&amp;rsquo;s saying it could use a little indexing help. And just the fact that I&amp;rsquo;m sometimes getting a &amp;ldquo;morally equivalent plan&amp;rdquo; is an indication to me that I haven&amp;rsquo;t forced something that&amp;rsquo;s perfect, I should look deeper.&lt;/p&gt;
&lt;p&gt;I love that!&lt;/p&gt;
&lt;h2 id="i-didnt-come-up-with-the-term-morally-equivalent-plan"&gt;I didn&amp;rsquo;t come up with the term &amp;ldquo;morally equivalent plan&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;I heard this term from &lt;a href="http://www.sommarskog.se"&gt;Erland Sommarskog&lt;/a&gt;, who said that he heard the term for &lt;a href="https://www.linkedin.com/in/conorcunningham/"&gt;Conor Cunningham&lt;/a&gt;. I love that it&amp;rsquo;s unique, not an acronym (yet), and it seems like a good description to me - so let&amp;rsquo;s popularize it among those of us who talk about plans :)&lt;/p&gt;
&lt;p&gt;And if you&amp;rsquo;d like to play with the code for this, it is based on a sample from Jovan Popovic published under the MIT license: &lt;a href="https://gist.github.com/LitKnd/b4730bfb131074bb81488909444df3e5"&gt;grab it here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>New Free Posters &amp; Desktop Backgrounds for Download</title><link>https://kendralittle.com/2018/03/08/new-free-posters-desktop-backgrounds-for-download/</link><pubDate>Thu, 08 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/08/new-free-posters-desktop-backgrounds-for-download/</guid><description>&lt;h2 id="i-love-fun-desktop-wallpapers"&gt;I love fun desktop wallpapers&lt;/h2&gt;
&lt;p&gt;You may have noticed that there&amp;rsquo;s something about cartoons combined with SQL Server that makes me happy. Having those images on my desktop inspires me and helps me feel creative. Work &lt;em&gt;should&lt;/em&gt; involve fun.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/LitKnd/littlekendracomments/tree/main/SQLWorkbooks-Wallpaper-and-Posters"&gt;Get the download on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Posters-and-Desktop-Wallpapers-400-square-1.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="new-drawings-resolutions-and-posters"&gt;New drawings, resolutions, and posters&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve updated my production process, and it&amp;rsquo;s now easier than ever for me to make new wallpapers - and to export different resolutions.&lt;/p&gt;
&lt;p&gt;This means I&amp;rsquo;ve added &lt;em&gt;posters&lt;/em&gt;! I really wanted to do that, and I&amp;rsquo;m very excited.&lt;/p&gt;
&lt;p&gt;Each image now comes in multiple flavors, and it&amp;rsquo;s all in one downloadable file (zip)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Poster (pdf) - for US Letter sized paper&lt;/li&gt;
&lt;li&gt;Desktop wallpapers (jpg) in three resolutions:
&lt;ul&gt;
&lt;li&gt;1280 x 1040&lt;/li&gt;
&lt;li&gt;1920 x 1080&lt;/li&gt;
&lt;li&gt;3440 x 1440&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="got-another-size-that-youre-dying-for"&gt;Got another size that you&amp;rsquo;re dying for?&lt;/h2&gt;
&lt;p&gt;If a different resolution would really make your day, let me know in the comments. I can add popular resolutions to the download pack.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/LitKnd/littlekendracomments/tree/main/SQLWorkbooks-Wallpaper-and-Posters"&gt;Get the posters on GitHub.&lt;/a&gt;&lt;/p&gt;</description></item><item><title>EstimateRowsWithoutRowGoal helps you see: is it a statistics problem?</title><link>https://kendralittle.com/2018/03/07/estimaterowswithoutrowgoal-helps-you-see-is-it-a-statistics-problem/</link><pubDate>Wed, 07 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/07/estimaterowswithoutrowgoal-helps-you-see-is-it-a-statistics-problem/</guid><description>&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms"&gt;SQL Server Management Studio version 17.5&lt;/a&gt; adds a welcome feature for execution plans: a new visual attribute named EstimateRowsWithoutRowGoal.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Goal-with-a-ghost-defender-e1518799627672.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;EstimateRowsWithoutRowGoal was added to the XML for execution plans &lt;a href="https://support.microsoft.com/en-us/help/4051361/optimizer-row-goal-information-in-query-execution-plan-added-in-sql-se"&gt;as of SQL Server 2017 CU3&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="whats-a-row-goal"&gt;What&amp;rsquo;s a row goal?&lt;/h2&gt;
&lt;p&gt;Sometimes the SQL Server optimizer notices something in a query that indicates it&amp;rsquo;ll pull back a limited number of rows.&lt;/p&gt;
&lt;p&gt;This could be a TOP, an IN or exists clause, or something like a FAST hint on the query.&lt;/p&gt;
&lt;h2 id="a-simple-example-a-query-with-a-fast-hint"&gt;A simple example: a query with a FAST hint&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s our example query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReportYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReportYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RankByReportYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnby&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RankByReportYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameRank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RankByReportYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReportYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RankByReportYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="at-first-glance-the-plan-might-look-like-we-have-a-statistics-problem"&gt;At first glance, the plan might look like we have a statistics problem&lt;/h2&gt;
&lt;p&gt;Highlighting one of the bars flowing through the plan, there&amp;rsquo;s a big difference between the estimated number of rows and the actual number of rows.&lt;/p&gt;
&lt;p&gt;We might think this is a statistics issue at first glance.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/actual-plan-looks-like-a-statistics-problem-e1518805565535.png"&gt;
&lt;/figure&gt;
&lt;h2 id="you-can-now-confirm-if-theres-a-row-goal-at-play---but-you-need-to-go-into-operator-properties"&gt;You can now confirm if there&amp;rsquo;s a row goal at play - but you need to go into operator properties&lt;/h2&gt;
&lt;p&gt;One important thing to know is that the row goals don&amp;rsquo;t show up on those bars between queries or the tooltips in SSMS.&lt;/p&gt;
&lt;p&gt;You need to select an operator in the plan, then look at its properties.&lt;/p&gt;
&lt;p&gt;In this case, the properties show that if we hadn&amp;rsquo;t set a row goal, the estimated number of rows would have been a whole lot closer to the actual rows&amp;ndash; at least for &lt;em&gt;this&lt;/em&gt; operator in the plan.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/EstimateRowsWithoutRowGoal-e1518805591577.png"&gt;
&lt;/figure&gt;
&lt;h2 id="dont-just-look-at-row-goals-in-one-part-of-the-plan"&gt;Don&amp;rsquo;t just look at row goals in one part of the plan&lt;/h2&gt;
&lt;p&gt;If I go farther to the left in my plan, things are different for the nested loop join!&lt;/p&gt;
&lt;p&gt;At this point in the plan, the row goal is closer to the actual number of rows than the estimate would have been if the query didn&amp;rsquo;t have the fast hint.&lt;/p&gt;
&lt;p&gt;If we&amp;rsquo;re thinking about tuning this query, it helps to be aware of how the row goal may be impacting different parts of the plan, so the detailed information at the operator level is very helpful.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/nested-loop-join-row-goals-e1518805611441.png"&gt;
&lt;/figure&gt;
&lt;h2 id="does-estimaterowswithoutrowgoals-appear-in-estimated-plans"&gt;Does EstimateRowsWithoutRowGoals appear in estimated plans?&lt;/h2&gt;
&lt;p&gt;Yes. You get &amp;lsquo;Estimated Number of Rows&amp;rsquo; and &amp;lsquo;EstimateRowsWithoutRowGoal&amp;rsquo; in an estimated plan (but not &amp;lsquo;Actual Number of Rows&amp;rsquo;.&lt;/p&gt;
&lt;h2 id="does-estimaterowswithoutrowgoals-show-up-in-query-store"&gt;Does EstimateRowsWithoutRowGoals show up in Query Store?&lt;/h2&gt;
&lt;p&gt;Yes - you get &amp;lsquo;Estimated Number of Rows&amp;rsquo; and &amp;lsquo;EstimateRowsWithoutRowGoal&amp;rsquo; in the plan in Query Store, too.&lt;/p&gt;
&lt;h2 id="why-isnt-it-named-estimated-rows-without-row-goals"&gt;Why isn&amp;rsquo;t it named &amp;lsquo;Estimated Rows Without Row Goals?&amp;rsquo;&lt;/h2&gt;
&lt;p&gt;Maybe developers have to pay by the letter for property names these days? Just guessing.&lt;/p&gt;
&lt;h2 id="by-the-way-im-not-saying-you-should-use-fast-hints-everywhere"&gt;By the way, I&amp;rsquo;m not saying you should use FAST hints everywhere&lt;/h2&gt;
&lt;p&gt;FAST hints are simply a fun way to show and play with row goals.&lt;/p&gt;
&lt;p&gt;I dig more into these hints and other ways to set row goals in the course &lt;a href="https://kendralittle.com/course/query-tuning-with-hints-optimizer-hotfixes/"&gt;Query Tuning with Hints and Optimizer Hotfixes&lt;/a&gt;. If you just can&amp;rsquo;t get enough row goals, you can also check out &lt;a href="https://sqlperformance.com/2018/02/sql-plan/setting-and-identifying-row-goals"&gt;Paul White&amp;rsquo;s article on SQLPerformance.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-were-the-top-3-names-from-the-last-few-years"&gt;What were the top 3 names from the last few years?&lt;/h2&gt;
&lt;p&gt;Emma and Olivia are on top for names in the last few years.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/top-three-names-last-few-years-e1518805889342.png"&gt;
&lt;/figure&gt;
&lt;p&gt;It is interesting that we do have a lot more name diversity in the United States in recent years than we used to have. If you change the sorting up, there were 99,680 Linda&amp;rsquo;s born in 1947!&lt;/p&gt;
&lt;h2 id="want-to-play-with-this-sample-code"&gt;Want to play with this sample code?&lt;/h2&gt;
&lt;p&gt;Grab it &lt;a href="https://gist.github.com/LitKnd/ce13db77dea4f63be9135e1bc49e6b2f"&gt;from this gist&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Overheard: “I just think there’s not that many women who enjoy coding. And I say that based on my daughter, too.”</title><link>https://kendralittle.com/2018/03/07/overheard-i-just-think-theres-not-that-many-women-who-enjoy-coding-and-i-say-that-based-on-my-daughter-too/</link><pubDate>Wed, 07 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/07/overheard-i-just-think-theres-not-that-many-women-who-enjoy-coding-and-i-say-that-based-on-my-daughter-too/</guid><description>&lt;p&gt;I&amp;rsquo;m at the Microsoft MVP Summit in Redmond, Washington this week. This is a great event for learning from the folks building amazing new technology at Microsoft, giving feedback and representing the community, and meeting and learning from other MVPs from around the world.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Blog-post-on-women-in-tech-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;This is a week of optimism and inspiration and thinking about possibility.&lt;/p&gt;
&lt;p&gt;But this morning I got a reminder of the mindsets and assumptions that limit this possibility. That squash that inspiration. That make people, particularly women, think, &amp;ldquo;tech isn&amp;rsquo;t for me.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is an exploration of a comment that I found surprisingly &amp;ldquo;squashing.&amp;rdquo; This post isn&amp;rsquo;t about shaming any specific people (nobody is identified except for me), it&amp;rsquo;s about exploring my own beliefs and biases that led this comment to have such power over me. Writing this was part of my personal process of defusing those beliefs and biases.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="i-slid-into-breakfast-slightly-behind-schedule"&gt;I slid into breakfast slightly behind schedule&lt;/h2&gt;
&lt;p&gt;We get free breakfast at our hotels at this event. It&amp;rsquo;s served buffet style in an area reserved for MVPs. I wanted to grab a bite and then jump on the bus quickly to make the first session today, so I slid into a table by myself. Right away, I heard two men at the next table talking loudly about women in technology.&lt;/p&gt;
&lt;p&gt;This is an international event, but for the record these two were clearly from the United States. They weren&amp;rsquo;t yelling, but they were speaking loudly and they sounded irritated.&lt;/p&gt;
&lt;p&gt;One of the men was talking about how women didn&amp;rsquo;t come to his user group. He said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There&amp;rsquo;s nothing keeping them from coming to my user group.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then he said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I just think there’s not that many women who enjoy coding. And I say that based on my daughter, too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="i-was-flooded-with-anger"&gt;I was flooded with anger&lt;/h2&gt;
&lt;p&gt;Almost immediately, I landed in a place between two urges: a urge to stand up and yell, and also a big fear response, too. The kind of fear response which triggers chemicals in your body and you can really &lt;em&gt;feel&lt;/em&gt; it.&lt;/p&gt;
&lt;p&gt;I knew I wasn&amp;rsquo;t going to be able to say anything coherent in that moment. I wasn&amp;rsquo;t going to open anyone&amp;rsquo;s mind, because this comment connected me with the culture of &amp;ldquo;Nice/Pretty/Good Girls Aren&amp;rsquo;t Smart&amp;rdquo; which runs deep.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a kid anymore. I&amp;rsquo;m in my 40&amp;rsquo;s, and if someone calls me &amp;ldquo;Miss,&amp;rdquo; I look behind me to see who they&amp;rsquo;re talking to. I&amp;rsquo;ve developed some toughness over this time. But I still had a moment where I considered bailing out on the day and heading home early.&lt;/p&gt;
&lt;p&gt;And then I mentally kicked myself and informed myself that I could throw this guy&amp;rsquo;s crappy expectations out of my head.&lt;/p&gt;
&lt;h2 id="why-did-i-get-so-mad"&gt;Why did I get so mad?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been fortunate in life: my parents told me I could do anything I want, and they &lt;em&gt;expected&lt;/em&gt; me to do great things. They frequently told me that I was smart - when I was a toddler, an awkward pre-teen, and a particularly obnoxious teenager (there were some rough years) - my parents set high expectations for me and they kept on telling me I was smart. Even after I did dumb things.&lt;/p&gt;
&lt;p&gt;I took this for granted as a kid. I rolled my eyes at it as a teenager. As an adult I am incredibly grateful they did this -  because I was getting a lot of other messages from the media, from other kids, from friends&amp;rsquo; parents and even sometimes from teachers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cool girls aren&amp;rsquo;t smarter than the boys&lt;/li&gt;
&lt;li&gt;Girls can be good at things that are feminine, like literature and writing, but boys are just better at math and science&lt;/li&gt;
&lt;li&gt;Women shouldn&amp;rsquo;t be pushy. (The word &amp;ldquo;pushy&amp;rdquo; is a way to make &amp;ldquo;persistent and self-driven&amp;rdquo; into something negative, and the word is almost always used to describe women.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These messages aren&amp;rsquo;t usually consciously sent, they are often accidentally said. They come from both men and women. These messages are still a hugely strong part of our culture.&lt;/p&gt;
&lt;p&gt;I know, because I still fight against these feelings. &lt;em&gt;I shouldn&amp;rsquo;t seem too smart in front of other people. Nobody likes a woman who shows off. It&amp;rsquo;s my role to make other people comfortable, not to challenge them. I should shut up and be quieter, I&amp;rsquo;m a girl. I&amp;rsquo;m supposed to be supportive, not a leader.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I got angry because the belief that &amp;ldquo;women just don&amp;rsquo;t like coding&amp;rdquo; is a manifestation of the cultural norm that women simply aren&amp;rsquo;t suited to being smart, that women are here for bringing comfort, not for blazing new trails. &lt;em&gt;Women just don&amp;rsquo;t like it! How could they invent and lead when they&amp;rsquo;re so busy putting on makeup?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There is a relationship between these two statements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;There&amp;rsquo;s not that very many women who enjoy coding&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;She&amp;rsquo;s such a nerdy freak, she thinks she can do this stuff. And she&amp;rsquo;s ugly.&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first statement is completely ignorant that women in the United States are getting the second statement all the time, both blatantly and subtly (often complete with unrelated personal insults, usually on appearance - because we love to judge women on appearance in our culture).&lt;/p&gt;
&lt;p&gt;The first statement rolls around in that ignorance and blissfully declares that it&amp;rsquo;s simply in women&amp;rsquo;s nature to not participate in a critical part of the most powerful and transformative industry that humans have ever invented.&lt;/p&gt;
&lt;h2 id="expectations-shape-reality"&gt;Expectations shape reality&lt;/h2&gt;
&lt;p&gt;All those times when my mom or dad told me I was smart and I rolled my eyes, I still heard them. Those expectations sank in, even when I just had a sarcastic response. Those are the expectations that made my reality today. I work in technology. I run my own business. I wouldn&amp;rsquo;t be doing this if it my parents hadn&amp;rsquo;t drilled it into me that I am smart.&lt;/p&gt;
&lt;p&gt;But yet, I still have those crappy cultural expectations in my head. I still have to constantly fight the feeling that I would be much better at this stuff if I was a guy.&lt;/p&gt;
&lt;p&gt;And I sometimes have to squelch thoughts that censure other women for being bold, for being outspoken, for being brave leaders, for being unashamedly inventive and brilliant, for being the smartest person in the room.&lt;/p&gt;
&lt;p&gt;That guy&amp;rsquo;s crappy expectations made me so mad, because I still share them in some shadowy way, and I constantly have to correct for them.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to judge this anonymous MVP&amp;rsquo;s daughter. I am going to hope for her that someone in her life repeatedly tells her that she&amp;rsquo;s smart. And even better: that someone tells her she&amp;rsquo;s a leader, that she&amp;rsquo;s brilliant, that she has everything she needs to change the world with technology, with math, with her brain, and that she can start doing that &lt;em&gt;whenever she wants&lt;/em&gt;. That she&amp;rsquo;s going to do remarkable things in her life, and she&amp;rsquo;s in control. Again, and again, and again.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Interests&amp;rdquo; usually don&amp;rsquo;t just come from inside us. Our interests are hugely shaped by what people tell us we can do, and how that fits in with all the crappy cultural messages we are &lt;em&gt;ever so slowly&lt;/em&gt; evolving away from.&lt;/p&gt;
&lt;h2 id="my-mission-raise-my-expectations-because-we-deserve-it"&gt;My mission: raise my expectations, because we deserve it&lt;/h2&gt;
&lt;p&gt;A lot of my thoughts after this morning are around the question, &amp;ldquo;Is there something I could have said to change that guy&amp;rsquo;s mind?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But the more I sit with this and write through it, I realize: that guy doesn&amp;rsquo;t matter.&lt;/p&gt;
&lt;p&gt;The important thing is to change my own mind, and to evolve my own thought patterns. To not let his voice and the voices around him dim my love of coding / technology / geeking out. Instead, to bounce off those voices and be more inspired to do awesome work.&lt;/p&gt;
&lt;p&gt;The important thing is to try to increase the messages to women in our culture: s_mart is the new beautiful, and YOU ARE SMART_. I love it when you&amp;rsquo;re the smartest person in the room.&lt;/p&gt;
&lt;p&gt;The important thing is to set high expectations for myself and my fellow women, and to have good assumptions about us, because we deserve those expectations and assumptions!&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s what I wanted to start doing more of in this post.&lt;/p&gt;
&lt;h2 id="but-theres-not-that-many-women-who-code-added-march-11"&gt;But there&amp;rsquo;s not that many women who code (added March 11)&lt;/h2&gt;
&lt;p&gt;A couple of folks in the comments have made the point that there are not that many women who are developers in technology, but there are women in other roles in IT &amp;ndash; and that I overheard a statement of fact.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m up late and I&amp;rsquo;m in a cheerful, story-writing mood* inspired by a recent book I read, so take a quick break for a thought experiment with me!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*FYI, I am not the same Kendra Little who writes romance novels. I haven&amp;rsquo;t read the novels (YET!) but I&amp;rsquo;m guessing they are WAY juicier than this.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Imagine this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An uber wealthy group of women decide to start a new experimental culture&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;They buy a private island, pay to outfit it with great infrastructure, and recruit a group of young women engineers and a few men to join their experiment, in which they are going to change the way society works.&lt;/p&gt;
&lt;p&gt;T&lt;strong&gt;he new society is based on a model where the adult women primarily work at a software engineering company&lt;/strong&gt; on the island, making games that are sold around the world. The internet and media on the island is tightly filtered for everyone else to protect the experiment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The men on the island primarily work building things&lt;/strong&gt;, and also running the homes on the island.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The children are taught that men are suited to do things like build homes and structures&lt;/strong&gt;, farming and gardening, raising animals and taking care of houses. They are told this is because men are very active and are naturally suited to moving around a lot and thinking in shapes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The children are taught that women are suited to tasks that require using computers, math, and coding&lt;/strong&gt;, because women are good at communicating with one another, resolving problems, and being creative together about engineering complex solutions.&lt;/p&gt;
&lt;p&gt;When the children are very young, they do a lot of things together as they begin to learn, but they learn that boys like blue and wear pants (the better to build things in) and girls like pink and wear skirts (much more suited to sitting and thinking hard).&lt;/p&gt;
&lt;p&gt;Once the kids start getting toward the pre-teen years, kids start to tease easy other, and the genders start to split more into groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Boys who like to play on the computer are called &amp;ldquo;girly-boys&amp;rdquo; and are mocked for not being manly&lt;/strong&gt;. The kids all have some computer classes for basic literacy, but boys who do too well at it are teased by some of the mean girls, who say, &amp;ldquo;I&amp;rsquo;d never date HIM, he thinks he&amp;rsquo;s a girl.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When a boy has a hard time on his homework for computer class,&lt;/strong&gt; &lt;strong&gt;his father says, &amp;ldquo;That&amp;rsquo;s OK, son. I was never good at that stuff either. Your sister is great at it, but you&amp;rsquo;re really good at building things.&amp;rdquo;&lt;/strong&gt; (Dad really never did see the attraction in it, I guess that&amp;rsquo;s why he signed up to come to this island.)&lt;/p&gt;
&lt;p&gt;Most of the boys follow their role models in life. They pair up with someone they enjoy and they find some work that they like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But there are still some boys who like coding so much that they persevere- because they don&amp;rsquo;t like building very much.&lt;/strong&gt; Even though they get teased, they persist at learning it. Some of them give up and go back to doing more traditional manly things, but a few boys stick with technology and do well.&lt;/p&gt;
&lt;p&gt;Some of the young men start to land jobs at the software engineering company! It can be a little lonely working in the development team at times, because most of the guys around are working in facilities, or they move furniture around the office, or they&amp;rsquo;re project managers (men plan a lot of the things they build, so they&amp;rsquo;re natural project managers), but the older men aren&amp;rsquo;t coders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The women software developers all seems to speak the same language.&lt;/strong&gt; Some of them try to be nice, but they get frustrated because they find the young men harder to communicate with. They just don&amp;rsquo;t seem to understand things as fast, and when a lot of women are having a high paced technical conversation, a lot of times the young men don&amp;rsquo;t even talk a lot.&lt;/p&gt;
&lt;p&gt;But the men still keep trying. The software development company needs more developers, and the young men try to talk management into training and recruiting more young men.&lt;/p&gt;
&lt;p&gt;The men worked really hard to get where they were, and they want to help other men &amp;ndash; and make the software company even better.&lt;/p&gt;
&lt;p&gt;One day at lunch, one young male developer sits next to two young women who are talking loudly. One of the women complains, in a loud, frustrated voice, &amp;ldquo;&lt;strong&gt;There&amp;rsquo;s nothing keeping these guys from coming to my user group. I just think there&amp;rsquo;s not that many men who enjoy coding.&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In both this story and in real life, the claim is about what people &lt;em&gt;enjoy&lt;/em&gt; based on their gender.&lt;/p&gt;
&lt;p&gt;Remember the Barbie doll who said, &amp;ldquo;Math class is tough! Party dresses are fun! I&amp;rsquo;ll always be here to help you! Do you have a crush on anyone?&amp;rdquo; That happened in 1992. The Barbie was marketed towards teens.&lt;/p&gt;
&lt;p&gt;Remember Computer Engineer Barbie, who&amp;rsquo;s only computer skill seemed to be getting a virus on her laptop? She had to have the laptop fixed by two boys, who also were the ones doing the programming. That was 2013.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying the Barbies are the cause of all this. I&amp;rsquo;m saying they&amp;rsquo;re just characters in this story - the story we tell our kids about what girls do and what boys do.&lt;/p&gt;
&lt;p&gt;The story that explains why the fact that having few women developers does not mean that women do not &lt;em&gt;like&lt;/em&gt; coding.&lt;/p&gt;
&lt;p&gt;Oh, and the book that inspired this thought experiment is &lt;a href="https://en.wikipedia.org/wiki/The_Power_(Alderman_novel)"&gt;&amp;ldquo;The Power&amp;rdquo; by Naomi Alderman&lt;/a&gt;. It&amp;rsquo;s an interesting read, a real page turning, and enjoyable whether or not you give a hoot about coding.&lt;/p&gt;</description></item><item><title>Forced Plan Confusion: Is_Forced vs Use Plan = True</title><link>https://kendralittle.com/2018/03/05/forced-plan-confusion-is_forced-vs-use-plan-true/</link><pubDate>Mon, 05 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/05/forced-plan-confusion-is_forced-vs-use-plan-true/</guid><description>&lt;p&gt;Identifying that a query plan has been bossed around in Query Store can be a bit tricky, because it can appear in different ways.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is a long post, but there is a recap at the bottom if you&amp;rsquo;re short on time. Or just vote up my suggestion to make this easier to see: &lt;a href="https://feedback.azure.com/forums/908035-sql-server/suggestions/33562136-indicate-morally-equivalent-forced-plan-where-us"&gt;vote here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="1-the-original-forcer-plan"&gt;1. The &amp;ldquo;Original FORCER&amp;rdquo; plan&lt;/h2&gt;
&lt;p&gt;This type of forced plan will have a check mark in its bubble on the graphical Query Store reports, and also have is_forced = 1 in sys.query_store_plan.&lt;/p&gt;
&lt;p&gt;However, this type of forced plan will NOT have &amp;ldquo;Use plan&amp;rdquo; = true in the properties of the top leftmost operator.&lt;/p&gt;
&lt;h2 id="2-the-slightly-different-forcee-plan"&gt;2. The &amp;ldquo;Slightly Different FORCEE&amp;rdquo; plan&lt;/h2&gt;
&lt;p&gt;This type of forced plan with NOT have a check mark on in its bubble on the Query Store reports, and will NOT have is_forced = 1 in sys.query_store plan.&lt;/p&gt;
&lt;p&gt;But it WILL have &amp;ldquo;Use plan&amp;rdquo; = true in the properties of the top leftmost operator.&lt;/p&gt;
&lt;h2 id="i-see-these-differences-both-if-a-plan-is-manually-forced-or-if-im-using-automatic-tuning"&gt;I see these differences both if a plan is manually forced, or if I&amp;rsquo;m using Automatic Tuning&lt;/h2&gt;
&lt;p&gt;Whether or not you have the 2017 Automatic Plan Correction feature enabled (part of Auto-Tuning), you&amp;rsquo;re clicking the graphical &amp;ldquo;Force Plan&amp;rdquo; button in the Query Store reports, or you&amp;rsquo;re running sys.sp_query_store_force_plan, you will see these differences.&lt;/p&gt;
&lt;h2 id="lets-take-a-look-at-a-demo"&gt;Let&amp;rsquo;s take a look at a demo&lt;/h2&gt;
&lt;p&gt;In this post, I&amp;rsquo;m going to show you how this works if I manually run sys.sp_query_store_force_plan. The demo code is at the bottom of the post and also supports letting Automatic Plan Correction force the plan, so you can run it either way and play with it for yourself.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="https://blogs.technet.microsoft.com/dataplatforminsider/author/jovan-popovic-msft/"&gt;Jovan Popovic&lt;/a&gt; of Microsoft for &lt;a href="https://github.com/Microsoft/sql-server-samples/blob/master/samples/features/automatic-tuning/force-last-good-plan/sql-scripts/demo-full.sql"&gt;publishing the original code under the MIT license&lt;/a&gt;. I adapted his code for this demo.&lt;/p&gt;
&lt;h2 id="this-is-a-parameter-sniffing-problem-first-we-get-the-fast-plan-in-cache"&gt;This is a parameter sniffing problem. First we get the &amp;lsquo;fast plan&amp;rsquo; in cache&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using manual plan forcing in Query Store for this demo, so first up I:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restore the WideWorldImporters sampled database from &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters-Full.bak&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Configure Query Store and make sure it&amp;rsquo;s enabled&lt;/li&gt;
&lt;li&gt;Make sure AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = OFF);&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then I start a workload. I have changed the demo slightly from Jovan&amp;rsquo;s original, and in our version we run a&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select avg([UnitPrice]*[Quantity])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; from Sales.OrderLines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; where PackageTypeID = @packagetypeid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@packagetypeid int&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;packagetypeid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We run this query 60 times.&lt;/p&gt;
&lt;p&gt;This gets a nested loop plan in cache for our query with an average CPU time of .06 milliseconds. Here&amp;rsquo;s what it looks like in the Top Resource Consumers Report:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-id-1-query-store-report-1024x497.png"&gt;
&lt;/figure&gt;
&lt;h2 id="but-now-we-have-a-recompile-and-a-different-parameter-is-sniffed"&gt;But now&amp;hellip; we have a recompile, and a different parameter is sniffed&lt;/h2&gt;
&lt;p&gt;Lots of things can cause a recompile: memory pressure, data in the tables changing, or someone running ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE.&lt;/p&gt;
&lt;p&gt;In this case, it&amp;rsquo;s the third one.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCOPED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONFIGURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLEAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROCEDURE_CACHE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Get slow plan in cache */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select avg([UnitPrice]*[Quantity])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; from Sales.OrderLines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; where PackageTypeID = @packagetypeid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@packagetypeid int&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;packagetypeid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The query that happens to compile now for our query has @packagetypeid = 0.&lt;/p&gt;
&lt;p&gt;This query doesn&amp;rsquo;t get a nested loop join, it gets a hash match join. It doesn&amp;rsquo;t take too long to run by itself, but unfortunately this plan is slow as dirt when it is reused for a value like @packagetypeid = 7.&lt;/p&gt;
&lt;p&gt;That runs 20 times, and this plan has an average CPU time of 389 seconds.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select avg([UnitPrice]*[Quantity])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; from Sales.OrderLines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; where PackageTypeID = @packagetypeid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@packagetypeid int&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;packagetypeid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="i-havent-enabled-automatic-plan-correction-but-i-get-a-suggestion"&gt;I haven&amp;rsquo;t enabled Automatic Plan Correction, but I get a suggestion&lt;/h2&gt;
&lt;p&gt;Because I&amp;rsquo;m on SQL Server 2017 and I have Query Store configured, sys.dm_db_tuning_recommendations has a little heads-up for me, if I know to look there.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/auto-tuning-suggestion-1024x327.png"&gt;
&lt;/figure&gt;
&lt;p&gt;It looks like I&amp;rsquo;ve got a plan re-use problem, aka &amp;lsquo;Bad Parameter Sniffing&amp;rsquo;.&lt;/p&gt;
&lt;h2 id="the-right-thing-to-do-would-be-to-look-into-why-im-getting-different-plans"&gt;The right thing to do &lt;em&gt;would&lt;/em&gt; be to look into why I&amp;rsquo;m getting different plans&lt;/h2&gt;
&lt;p&gt;If I were to do the right thing, I would try to figure out how to stabilize the plans without forcing anything.&lt;/p&gt;
&lt;p&gt;But this post isn&amp;rsquo;t about doing the right thing, it&amp;rsquo;s about forcing!&lt;/p&gt;
&lt;h2 id="lets-say-i-take-the-script-from-the-suggestion-and-manually-force-this-plan-with-tsql"&gt;Let&amp;rsquo;s say I take the script from the suggestion, and manually force this plan with TSQL&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have now forced plan_id 1!&lt;/p&gt;
&lt;p&gt;If I look at Top Resource Consumers, plan_id 1 now has a check mark by it:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-id-1-has-check-mark.png"&gt;
&lt;/figure&gt;
&lt;h2 id="after-forcing-the-plan-the-query-runs-some-more"&gt;After forcing the plan, the query runs some more&lt;/h2&gt;
&lt;p&gt;Our query just runs once, again with @packagetypeid = 7.&lt;/p&gt;
&lt;p&gt;This is the first time the query has run with @packagetypeid = 7 while being forced to use a plan compiled for @packagetypeid=7.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select avg([UnitPrice]*[Quantity])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; from Sales.OrderLines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; where PackageTypeID = @packagetypeid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@packagetypeid int&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;packagetypeid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="whoa-now-we-have-three-plans"&gt;Whoa, now we have THREE plans&lt;/h2&gt;
&lt;p&gt;Our query uses the forced plan, but, wow, it gets a new plan_id: 10. Here&amp;rsquo;s what plan_id 10 looks like with its plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-id-10-has-no-check-mark-1024x542.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Plan_id 10 has no check-mark, but it has been forced to use the nested loop plan shape.&lt;/p&gt;
&lt;p&gt;However, notice that it got a missing index request, and the bars in the plan are much thicker than the nested loop plan in the screenshot above.&lt;/p&gt;
&lt;h2 id="plan_id-10-is-a-forced-plan-but-it-was-compiled-for-packagetypeid7"&gt;Plan_id 10 is a forced plan, but it was compiled for @packagetypeid=7&lt;/h2&gt;
&lt;p&gt;If we look in the properties of the SELECT operator on plan_id 10, I can see a couple of things:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-id-10-plan-properties-1024x548.png"&gt;
&lt;/figure&gt;
&lt;h3 id="parameter-compiled-value"&gt;Parameter compiled value&lt;/h3&gt;
&lt;p&gt;In the Parameter List, @packagetypeid = 7. That is the value this was compiled for. That influenced the costing. That&amp;rsquo;s good, because there WERE more rows flowing into that stream aggregate. The higher estimates are also responsible for the green hint notifying us that we should take a look at our indexes, because it could be better.&lt;/p&gt;
&lt;h3 id="use-plan--true"&gt;Use plan = true&lt;/h3&gt;
&lt;p&gt;This plan was generated with a directive to use this plan shape. It didn&amp;rsquo;t just happen.&lt;/p&gt;
&lt;h2 id="plan-10not-forced"&gt;Plan 10[not forced]&lt;/h2&gt;
&lt;p&gt;Look right above the SELECT operator in the plan. It says &amp;ldquo;not forced&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;But, uh&amp;hellip;.. Use plan = true.&lt;/p&gt;
&lt;p&gt;If it wasn&amp;rsquo;t forced, it was leaned on pretty heavily!&lt;/p&gt;
&lt;p&gt;I read that &amp;ldquo;not forced&amp;rdquo; as, &amp;ldquo;This is the &lt;em&gt;exact&lt;/em&gt; plan that was forced.&amp;rdquo; To know if it was forced but has different costs, you have to look for that use_plan=true.&lt;/p&gt;
&lt;h2 id="heres-what-it-looks-like-in-sysquery_store_plan"&gt;Here&amp;rsquo;s what it looks like in sys.query_store_plan&lt;/h2&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sys.query_store_plan.png"&gt;
&lt;/figure&gt;
]&lt;/p&gt;
&lt;p&gt;The checkmark in the graphic Query Store reports is reflecting the plan which has is_forced_plan = 1.&lt;/p&gt;
&lt;p&gt;For plan_id 10, if you dig into the plan stored in the query_plan column in the DMV, you will find that &amp;ldquo;Use plan=true&amp;rdquo; property, just like we saw in the report.&lt;/p&gt;
&lt;h2 id="recap-plan-forcer-and-plan-forcee"&gt;Recap: Plan FORCER and Plan FORCEE&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t easy to summarize, but I&amp;rsquo;m going to give it my best shot!&lt;/p&gt;
&lt;p&gt;When plans are forced in Query Store, whether it&amp;rsquo;s done by a user or by Automatic Tuning, there is more than one type of &amp;ldquo;forced&amp;rdquo; plan.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plan FORCER&lt;/strong&gt;: The exact plan which is forced will show with a check mark in Query Store reports, and will have Is_Forced = 1 in sys.query_store_plan.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sometimes (probably often), you will see Slightly Different Plan FORCEEs&lt;/strong&gt;: Once a plan is forced, either&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;That exact plan can be compiled (which will have a checkmark and is_forced=1, it&amp;rsquo;s the same plan id), or &amp;hellip;&lt;/li&gt;
&lt;li&gt;Sometimes a slightly different FORCEE can be compiled with different costs and different row estimates. This has the same shape as the forced plan, but you&amp;rsquo;ll see different shaped bars in it, perhaps a missing index suggestion and different memory grants. This FORCEE plan does not show with a check mark, has Is_forced = 0, but &lt;em&gt;does&lt;/em&gt; have a plan property of &amp;lsquo;Use plan&amp;rsquo; = true on the top leftmost operator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I totally made up the words &amp;ldquo;FORCER&amp;rdquo; and &amp;ldquo;Slightly Different Plan FORCEE&amp;rdquo;, for the lack of better terms. And they make me laugh.&lt;/p&gt;
&lt;h2 id="wanna-play-with-it-yourself"&gt;Wanna play with it yourself?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;a href="https://gist.github.com/LitKnd/494008b7073374a634791f072326ad05"&gt;demo code in a gist&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="want-this-to-be-easier-to-see"&gt;Want this to be easier to see?&lt;/h2&gt;
&lt;p&gt;Vote up my suggestion to make this easier to see: &lt;a href="https://feedback.azure.com/forums/908035-sql-server/suggestions/33562136-indicate-morally-equivalent-forced-plan-where-us"&gt;vote here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Why I Love the Automatic Plan Correction Auto-Tuning Feature</title><link>https://kendralittle.com/2018/03/01/why-i-love-the-automatic-plan-correction-auto-tuning-feature/</link><pubDate>Thu, 01 Mar 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/03/01/why-i-love-the-automatic-plan-correction-auto-tuning-feature/</guid><description>&lt;p&gt;I&amp;rsquo;m thrilled to have just finished and published &lt;a href="https://kendralittle.com/course/automatic-plan-correction-in-query-store/"&gt;a new course on Automatic Tuning in SQL Server&lt;/a&gt;. This feature is available in SQL Server 2017+ and Azure SQL Database.&lt;/p&gt;
&lt;p&gt;Update: &lt;a href="https://kendralittle.com/course/automatic-plan-correction-in-query-store/"&gt;this course&lt;/a&gt; is now open and totally free to all.&lt;/p&gt;
&lt;h2 id="i-amway-more-excited-about-this-feature-than-i-thought-i-would-be"&gt;I am WAY more excited about this feature than I thought I would be&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Automatic-Plan-Correction-Course-Image-1.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Cynical me assumed&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This feature won&amp;rsquo;t be that cool&lt;/li&gt;
&lt;li&gt;It only works sometimes &amp;ndash; when you&amp;rsquo;ve actually had decent performance in the past!&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;ll probably be really clumsy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I shouldn&amp;rsquo;t be so cynical, because after working with this even for a short time, I started to see the magic.&lt;/p&gt;
&lt;h2 id="im-glad-i-was-wrong"&gt;I&amp;rsquo;m glad I was wrong&lt;/h2&gt;
&lt;p&gt;Yes, the feature only works sometimes. However, that&amp;rsquo;s because it&amp;rsquo;s NOT really clumsy. It&amp;rsquo;s quite thoughtful!&lt;/p&gt;
&lt;p&gt;Automatic Plan Correction is smart enough to test and verify its changes. It&amp;rsquo;s smart enough to back off what it&amp;rsquo;s done when you add an index, or when your data distribution changes, and then test and verify again.&lt;/p&gt;
&lt;p&gt;But this is OK, because it&amp;rsquo;s not trying to permanently fix things. It&amp;rsquo;s trying to make things better for a little while until YOU can step in and figure out a permanent fix!&lt;/p&gt;
&lt;h2 id="automatic-tuning-makes-it-much-easier-to-find-bad-parameter-sniffing"&gt;Automatic Tuning makes it much easier to find bad parameter sniffing&lt;/h2&gt;
&lt;p&gt;One of the trickiest performance problems that developers and DBAs face is figuring out &amp;ldquo;why was this thing slow two hours ago, but it&amp;rsquo;s fast now?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Many times, the answer to this is &amp;ldquo;bad parameter sniffing&amp;rdquo;: we had an execution plan in cache that was slow when the query was executed with a variety of different parameter values.&lt;/p&gt;
&lt;p&gt;This is hard to identify because often a different plan is currently in cache by the time we look at it. And even if we have fancy monitoring tools, it can be tricky to compare the average costs of the plans and determine which plan may be better.&lt;/p&gt;
&lt;p&gt;The Automatic Plan Correction feature is looking exactly for things like that.&lt;/p&gt;
&lt;p&gt;And that is a hard enough problem to detect that I see why this is an Enterprise Only feature. I get it.&lt;/p&gt;
&lt;h2 id="best-of-all-you-can-try-this-out-in-a-safe-way"&gt;Best of all, you can try this out in a safe way&lt;/h2&gt;
&lt;p&gt;You can either let Automatic Plan Correction test out changes for you, or just look at its recommendations.&lt;/p&gt;
&lt;p&gt;The recommendations contain pretty rich detail about the problem it observed, the regressed plan, and the plan that looks like it would be better. You can take that information and use it with Query Store to devise your own fix safely.&lt;/p&gt;
&lt;p&gt;Pretty cool.&lt;/p&gt;</description></item><item><title>Can I Force Multiple Plans for a Query in Query Store?</title><link>https://kendralittle.com/2018/02/28/can-i-force-multiple-plans-for-a-query-in-query-store/</link><pubDate>Wed, 28 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/28/can-i-force-multiple-plans-for-a-query-in-query-store/</guid><description>&lt;p&gt;Nope.&lt;/p&gt;
&lt;p&gt;At least, not right now.&lt;/p&gt;
&lt;p&gt;I started thinking about this when I noticed that the sys.sp_query_store_unforce_plan requires you to specify both a @query_id and a @plan_id.&lt;/p&gt;
&lt;p&gt;If there&amp;rsquo;s only ever one plan that can be forced for a query, why would I need to specify the @plan_id?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got no insider knowledge on this, I just started thinking about it.&lt;/p&gt;
&lt;h2 id="current-behavior-sql-server-2017-allows-you-to-run-syssp_query_store_force_plan-multiple-times-for-the-same-query_id-but"&gt;Current behavior: SQL Server 2017 allows you to run sys.sp_query_store_force_plan multiple times for the same @query_id, but&amp;hellip;&lt;/h2&gt;
&lt;p&gt;It will only force the plan for the most recent statement you ran.&lt;/p&gt;
&lt;p&gt;If I have a query with id=4 which has two plans with plan ids 3, and 5, and I run this TSQL all at once:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sp_query_store_force_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For a brief moment after the first statement runs, @plan_id 3 will be forced.&lt;/p&gt;
&lt;p&gt;After both statements complete, only @plan_id 5 will be forced.&lt;/p&gt;
&lt;p&gt;There can only be one!&lt;/p&gt;
&lt;h2 id="why-would-it-be-cool-to-be-able-to-force-more-than-one-plan"&gt;Why would it be cool to be able to force more than one plan?&lt;/h2&gt;
&lt;p&gt;We might have a parameterized query that we want multiple plans for, depending on how it&amp;rsquo;s executed.&lt;/p&gt;
&lt;p&gt;The query is executed with @parameter_x = null, I want Plan A.&lt;/p&gt;
&lt;p&gt;Otherwise I want Plan B.&lt;/p&gt;
&lt;p&gt;Could be nifty!&lt;/p&gt;
&lt;h2 id="it-is-possible-that-plan_id-is-required-to-prevent-accidents"&gt;It is possible that @plan_id is required to prevent accidents&lt;/h2&gt;
&lt;p&gt;Perhaps it&amp;rsquo;s required to specify the @plan_id in case I make a mistake, and specify the wrong query id for a plan id, and it wants to make sure I &lt;em&gt;really have it right&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible, but doesn&amp;rsquo;t seem super likely to me. I&amp;rsquo;d rather optimistically hope that some day plan forcing will become even more flexible.&lt;/p&gt;
&lt;p&gt;Will it ever happen? I have no idea :smile:&lt;/p&gt;</description></item><item><title>Infographic: Conference Prep for Anxious Folk</title><link>https://kendralittle.com/2018/02/26/infographic-conference-prep-for-anxious-folk/</link><pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/26/infographic-conference-prep-for-anxious-folk/</guid><description>&lt;p&gt;I&amp;rsquo;m honored to be heading to &lt;a href="https://mvp.microsoft.com/summit"&gt;the Microsoft MVP Summit&lt;/a&gt;. I really enjoy this conference&amp;ndash; it&amp;rsquo;s not my first time going, so I know the ropes. I&amp;rsquo;m looking forward to seeing a bunch of old friends AND to connect to lots and lots of new people.&lt;/p&gt;
&lt;p&gt;But even though I am familiar with the conference, I have a list of things I do to get ready and prepare. That&amp;rsquo;s because&amp;hellip;&lt;/p&gt;
&lt;h2 id="conferences-tend-to-make-me-socially-anxious"&gt;Conferences tend to make me socially anxious&lt;/h2&gt;
&lt;p&gt;While I LOVE meeting new people, I can get pretty nervous about it.&lt;/p&gt;
&lt;p&gt;I also often have a hard time sleeping when I travel, especially on the first few nights of the trip. If I don&amp;rsquo;t take care, I can end up &amp;ldquo;replaying&amp;rdquo; a lot of conversations in my head, analyzing whether or not I may have accidentally said the wrong thing or misunderstood someone.&lt;/p&gt;
&lt;p&gt;If I fall into that trap, then the lack of sleep tends to build my anxiety the next day and&amp;hellip; you can see the spiral of anxiety forming, right?&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m happy to say that it doesn&amp;rsquo;t have to be this way!&lt;/p&gt;
&lt;h2 id="habits-and-preparation-help-me-have-a-great-time-at-conferences"&gt;Habits and preparation help me have a great time at conferences&lt;/h2&gt;
&lt;p&gt;I talked about this a bit &lt;a href="https://kendralittle.com/2017/11/08/dear-sql-dba-i-thought-i-was-an-introvert-turns-out-i-was-anxious-as/"&gt;on a podcast episode a while back&lt;/a&gt;: I&amp;rsquo;ve learned to understand my anxiety better.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also learned simple, practical things that I can do to help me relax more fully, sleep better, feel calmer and more optimistic in social situations, and how to get myself in the right mindset to be successful at a big social event, like a conference.&lt;/p&gt;
&lt;h2 id="im-not-a-doctor-and-im-still-evolving"&gt;I&amp;rsquo;m not a doctor, and I&amp;rsquo;m still evolving&lt;/h2&gt;
&lt;p&gt;I just evolved a little by making this infographic. Wow, that was really fun! So lookout, there&amp;rsquo;s about to be a lot more infographics around here, like it&amp;rsquo;s 2015 all over again ;)&lt;/p&gt;
&lt;p&gt;Everyone has different needs, and my methods won&amp;rsquo;t magically cure everyone&amp;rsquo;s anxiety. This infographic certainly isn&amp;rsquo;t medical advice.&lt;/p&gt;
&lt;p&gt;But I hope that the infographic inspires you - either to try some of these techniques yourself, or to try your own ideas to help bring more balance, optimism, and calm into your busy, conference-going life.&lt;/p&gt;
&lt;h2 id="see-the-infographic-pdf"&gt;See the infographic (pdf)&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/images/Infographic_-Conference-Prep-for-Anxious-Folk.pdf"&gt;Infographic_-Conference-Prep-for-Anxious-Folk.pdf&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Using YouTube Captions &amp; Transcript to Find Content in a Long Video</title><link>https://kendralittle.com/2018/02/23/using-youtube-captions-transcript-to-find-content-in-a-long-video/</link><pubDate>Fri, 23 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/23/using-youtube-captions-transcript-to-find-content-in-a-long-video/</guid><description>&lt;p&gt;This week, I was pretty pumped to see that PASS published Erin Stellato (&lt;a href="https://twitter.com/erinstellato"&gt;twitter&lt;/a&gt;) and Dejan Krakovic&amp;rsquo;s (&lt;a href="https://www.linkedin.com/in/dejan-krakovic-12339314b/"&gt;linked in&lt;/a&gt;) excellent session on Query Store to the public.&lt;/p&gt;
&lt;p&gt;I attended this session live at the conference, and I remembered that there was one specific part on memory limits in Query Store that I wanted to watch again. I&amp;rsquo;d jotted down a note about it, but things were flying by and my note was gibberish.&lt;/p&gt;
&lt;p&gt;The recording is 75 minutes long, and it&amp;rsquo;s a great session, but I wanted to just find this one part at the moment. However, I couldn&amp;rsquo;t remember if the comment was early or late in the session.&lt;/p&gt;
&lt;h2 id="transcripts-to-the-rescue"&gt;Transcripts to the rescue!&lt;/h2&gt;
&lt;p&gt;Transcripts are kinda hard to see in YouTube, and I only discovered them when I was playing around with YouTube in the process of captioning my own videos.&lt;/p&gt;
&lt;p&gt;To open transcripts, I had to click on the &amp;lsquo;&amp;hellip;&amp;rsquo; in my browser, then select open Transcript. That gets it open in a pane of its own:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/youtube-open-transcript-1024x543.png"&gt;
&lt;/figure&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re on mobile, you may well get a different UI experience and have to tap elsewhere. My general practice is just to rub my forehead against the phone until it works.&lt;/p&gt;
&lt;h2 id="click-in-the-transcript-box-and-use-find-in-your-browser"&gt;Click in the transcript box, and use Find in your browser&lt;/h2&gt;
&lt;p&gt;The transcript for YouTube videos is generally automatically generated, so you may need a little creativity or luck here.&lt;/p&gt;
&lt;p&gt;I knew I wanted to find a reference to &amp;lsquo;memory&amp;rsquo;, and it seemed like a good word to search on because it doesn&amp;rsquo;t have a lot of homonyms. I guess it could be auto-transcribed as &amp;lsquo;mammary&amp;rsquo;, which would be hilarious, but in this case the computers got it right.&lt;/p&gt;
&lt;p&gt;The whole transcript loaded in the page for me, so I found all 18 memory occurrences, and was able to page through them.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/woo-hoo-found-it-1024x457.png"&gt;
&lt;/figure&gt;
&lt;h2 id="use-the-timestamps-to-get-to-that-point-in-the-video"&gt;Use the timestamps to get to that point in the video!&lt;/h2&gt;
&lt;p&gt;The timestamps helpfully showed that the portion of the video I wanted to watch is around 37 minutes in, and I was able to &lt;a href="https://youtu.be/r3k3mrnk-cQ?t=38m20s"&gt;go straight there&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="so-what-is-this-part-of-the-video-about"&gt;So, what is this part of the video about?&lt;/h2&gt;
&lt;p&gt;There is a question from the audience about the performance impact of running Query Store.&lt;/p&gt;
&lt;p&gt;Dejan gives an answer that points out that the overhead is often minimal, but you may run into special situations if you have a workload that generates a lot of unique query plans (such as a non-parameterized workload). &lt;a href="https://youtu.be/r3k3mrnk-cQ?t=38m20s"&gt;I won&amp;rsquo;t spoil it, watch it for more info &amp;ndash; for the portion on the safety memory limit, watch until  38:42&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="thanks-to-erin-stellato-dejan-krakovic-and-to-pass-for-publishing-this-video"&gt;Thanks to Erin Stellato, Dejan Krakovic, and to PASS for publishing this video!&lt;/h2&gt;
&lt;p&gt;I loved the session live, and it&amp;rsquo;s great to have it online to reference and share with others.&lt;/p&gt;
&lt;p&gt;You can watch &lt;a href="http://www.pass.org/summit/2018/Sessions/BestOfSummit.aspx"&gt;even more free videos from the PASS Summit 2018 right here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>When Should I Use Explicit Transactions for Single Statements?</title><link>https://kendralittle.com/2018/02/22/when-should-i-use-explicit-transactions-for-single-statements/</link><pubDate>Thu, 22 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/22/when-should-i-use-explicit-transactions-for-single-statements/</guid><description>&lt;p&gt;I got a great question about transactions by email recently about transactions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When should you use transactions?&lt;/p&gt;
&lt;p&gt;From what I have read online the answer is whenever you can, but I haven&amp;rsquo;t found a good why answer.&lt;/p&gt;
&lt;p&gt;I understand that you should be using them when you want a set of events to succeed or fail. But what if you just have a &lt;em&gt;single statement&lt;/em&gt; that doesn&amp;rsquo;t depend on other statements - why should you use transactions?&lt;/p&gt;
&lt;p&gt;We have experienced some errors when we used them and so I was wondering what merits does it have that make it worth the code maintenance, especially since SQL Server implicitly creates transactions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Part of why this is extra confusing is that there are &lt;em&gt;three&lt;/em&gt; types of transactions. First up, let&amp;rsquo;s clarify a few terms.&lt;/p&gt;
&lt;h2 id="explicit-vs-implicit-vs-autocommit-transactions"&gt;Explicit vs. Implicit vs. Autocommit Transactions&lt;/h2&gt;
&lt;h2 id="1-explicit-transactions"&gt;1. Explicit transactions&lt;/h2&gt;
&lt;p&gt;This is the type of transaction where you explicitly start the transaction with &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/language-elements/begin-transaction-transact-sql"&gt;BEGIN TRAN or BEGIN TRANSACTION&lt;/a&gt;, and later complete the work with either a &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/language-elements/commit-work-transact-sql"&gt;COMMIT&lt;/a&gt; statement or undo it with a &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/language-elements/rollback-transaction-transact-sql"&gt;ROLLBACK&lt;/a&gt; statement.&lt;/p&gt;
&lt;p&gt;As our questioner writes, if you have multiple statements that should either succeed or fail as an individual unit, BEGIN TRAN allows you to bundle them together.&lt;/p&gt;
&lt;h2 id="2-implicit-transactions"&gt;2. Implicit transactions&lt;/h2&gt;
&lt;p&gt;Implicit transactions are a bit weird, and I typically only run into them when applications have been written for a different relational database and then ported to SQL Server.&lt;/p&gt;
&lt;p&gt;To use implicit transactions, you run the statement: &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql"&gt;SET IMPLICIT_TRANSACTIONS ON&lt;/a&gt;;&lt;/p&gt;
&lt;p&gt;This puts you in a mode where running a statement which accesses a table implies that you ran BEGIN TRAN. You must explicitly COMMIT or ROLL BACK when you&amp;rsquo;re done with a unit of work, whether it&amp;rsquo;s one or more statements.&lt;/p&gt;
&lt;p&gt;I find implicit transactions confusing, and I don&amp;rsquo;t use it.&lt;/p&gt;
&lt;h2 id="3-autocommit-transactions"&gt;3. Autocommit transactions&lt;/h2&gt;
&lt;p&gt;If you do not enable implicit transactions, and you don&amp;rsquo;t start an explicit transaction, you are in the default &amp;ldquo;autocommit&amp;rdquo; mode.&lt;/p&gt;
&lt;p&gt;This mode means that individual statements are automatically committed or rolled back as whole units. You can&amp;rsquo;t end up in a place where only half your statement is committed.&lt;/p&gt;
&lt;p&gt;Our question is really about whether there are unseen problems with this default mode of autocommit for single-statement units of work.&lt;/p&gt;
&lt;p&gt;So, to rephrase the question&amp;hellip;&lt;/p&gt;
&lt;h2 id="are-there-times-when-we-should-use-an-explicit-transaction-for-single-statements-instead-of-relying-on-autocommit"&gt;Are there times when we should use an explicit transaction for single statements, instead of relying on autocommit?&lt;/h2&gt;
&lt;p&gt;Generally, you&amp;rsquo;re fine staying in the default autocommit mode for singleton statements that are entirely their own unit of work.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve fun into a few instances where creating a larger unit of work for modifications helped performance, however! Example: are you doing a lot of tiny modifications?&lt;/p&gt;
&lt;h2 id="sometimes-you-get-better-performance-bundling-multiple-statements-into-a-transaction"&gt;Sometimes you get better performance bundling multiple statements into a transaction&lt;/h2&gt;
&lt;p&gt;Way back when I was a Junior DBA, there was a project to modify a lot of data in our OLTP database. We had a big change coming up which required a lot of new data to be present, and some data to be modified for customers.&lt;/p&gt;
&lt;p&gt;We couldn&amp;rsquo;t have much downtime for the change, so a plan was hatched to get the data all set up in production while the system was live, then to cut over to the new feature as the actual change. This was tested out in staging, and everything was great, but slow.&lt;/p&gt;
&lt;p&gt;The staging environment was generally slow, so that didn&amp;rsquo;t mean much by itself.&lt;/p&gt;
&lt;p&gt;But by the time we got to deploy the change to production, it was slow as well. Luckily, we had a plan to make it faster.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Indexes had been deployed to help make the modifications as fast as possible&lt;/li&gt;
&lt;li&gt;The scripts to make the data changes were set up to be able to be safely stopped at any time and restarted, in case of blocking problems or any concern about performance&lt;/li&gt;
&lt;li&gt;The scripts had a @BatchSize parameter, which allowed the DBAs to determine how many modification statements were run inside a single transaction&lt;/li&gt;
&lt;li&gt;The scripts had a @WaitDuration parameter, which allowed the DBAs to determine how many milliseconds to wait between batches&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each modification statement was a single unit of work, but the script ran faster when multiple modification statements were committed at once!  @BatchSize = 1 was &lt;em&gt;not&lt;/em&gt; awesome, it was very slow.&lt;/p&gt;
&lt;h2 id="this-is-because-lots-of-tiny-little-commits-can-put-a-lot-of-pressure-on-your-transaction-log-causing-a-bottleneck"&gt;This is because lots of tiny little commits can put a lot of pressure on your transaction log, causing a bottleneck&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s like wanting to read someone a long story, but making a phone call for every single word.&lt;/p&gt;
&lt;p&gt;If the person is very busy and can&amp;rsquo;t talk to only you for a whole hour, to the exclusion of everyone else, then you want to figure out how long they can spare for a call, and how many words you can fit into a single call.&lt;/p&gt;
&lt;p&gt;Amit Banerjee &lt;a href="https://troubleshootingsql.com/2011/07/27/performance-benchmarking-explicit-vs-implicit-transactions/"&gt;does a demo and breaks everything down in a great way in this classic post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="explicit-and-autocommit-transactions-show-up-differently-in-some-performance-counters"&gt;Explicit and autocommit transactions show up differently in some performance counters&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t think this is a reason to use explicit transactions, it&amp;rsquo;s just something to be aware of.&lt;/p&gt;
&lt;p&gt;The basics are this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modifications in autocommit mode and select statements in explicit transactions &lt;em&gt;both&lt;/em&gt; show up under Transactions/sec and Batch Requests/sec&lt;/li&gt;
&lt;li&gt;Select statements in autocommit mode do not show up under the Transactions/sec counter, but they DO show up under Batch Requests/sec&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can &lt;a href="https://kendralittle.com/2017/05/08/sqlserverdatabases_totaltransactionssec-vs-sql-statisticsbatch-requestssec-video/"&gt;watch a demo of it on my post here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Generally speaking, I think this is a reason to use the Batch requests/sec counter over Transactions/sec (not a reason to go adding transactions to all your singleton select statements).&lt;/p&gt;
&lt;h2 id="what-about-marked-transactions"&gt;What about marked transactions?&lt;/h2&gt;
&lt;p&gt;The idea behind &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/use-marked-transactions-to-recover-related-databases-consistently"&gt;marked transactions&lt;/a&gt; sounds pretty cool: you can mark a transaction as a recovery point.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say I&amp;rsquo;m releasing a big change that touches multiple databases. I could use marked transactions to allow me to restore those databases all to the mark, so that I could perhaps restore them to right before the change was deployed, or right after it was complete (depending on which I used).&lt;/p&gt;
&lt;p&gt;The reason I&amp;rsquo;m not crazy about using these &amp;ldquo;just in case,&amp;rdquo; or for very frequent use, is that there some overhead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They use space in your transaction logs in each database they touch&lt;/li&gt;
&lt;li&gt;They use space in msdb, and if you use a ton of these, you may need to do some maintenance there&lt;/li&gt;
&lt;li&gt;There is some complexity around using this with multiple instances (&lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/use-marked-transactions-to-recover-related-databases-consistently#forcing-a-mark-to-spread-to-other-servers"&gt;details here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m not against marked transactions if they meet a real need and the team has the time to monitor their overhead. For large releases that touch multiple databases, SAN snapshots are often more convenient (although obviously they are not tied to a transaction).&lt;/p&gt;</description></item><item><title>New SQLChallenge: Defuse the Deadlock</title><link>https://kendralittle.com/2018/02/20/new-sqlchallenge-defuse-the-deadlock/</link><pubDate>Tue, 20 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/20/new-sqlchallenge-defuse-the-deadlock/</guid><description>&lt;p&gt;When I first created SQLWorkbooks, I distilled what it was all about down into one sentence: &amp;ldquo;Learn SQL Server by Solving Problems.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This month, I introduce &lt;a href="course/defuse-the-deadlock-sqlchallenge/"&gt;my first SQLChallenge&lt;/a&gt;, which distills that down into practice. The SQLChallenge features 23 minutes of video with scripts that you can use to reproduce and solve the problem yourself.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQLChallenge-Defuse-the-Deadlock-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="defuse-the-deadlock"&gt;Defuse the Deadlock&lt;/h2&gt;
&lt;p&gt;In this &lt;a href="course/defuse-the-deadlock-sqlchallenge/"&gt;SQLChallenge&lt;/a&gt; , you get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scripts and a video showing you how to reproduce the deadlock&lt;/li&gt;
&lt;li&gt;A copy of the deadlock graph&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your challenge&lt;/strong&gt;&lt;/em&gt;: Design an index that prevents the deadlock from happening when the repro steps are run again&lt;/p&gt;
&lt;p&gt;After you’re done working on preventing the deadlock, watch the videos showing how I strategized the solutions, and indexes I tested that prevent the deadlock (you get these, too, in the solution script).&lt;/p&gt;
&lt;h2 id="additional-learning"&gt;Additional learning&lt;/h2&gt;
&lt;p&gt;In the videos where we defuse the deadlock together, you will learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Where the graphic deadlock may contain a lie&lt;/li&gt;
&lt;li&gt;Why dropping a near-duplicate index could cause a deadlock to happen&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="worried-youll-get-stuck"&gt;Worried you’ll get stuck?&lt;/h2&gt;
&lt;p&gt;Getting stuck is totally OK – it’s the struggle that gets you there in the end!&lt;/p&gt;
&lt;p&gt;If you get totally frustrated, go ahead and watch the solution videos.&lt;/p&gt;
&lt;p&gt;Then &lt;em&gt;set yourself a reminder&lt;/em&gt; to retake the challenge in one week’s time. Running through the challenge again will lock in the learning.&lt;/p&gt;
&lt;h2 id="what-if-i-need-to-learn-more"&gt;What if I need to learn more?&lt;/h2&gt;
&lt;p&gt;I wouldn&amp;rsquo;t leave you without a safety net.&lt;/p&gt;
&lt;p&gt;&lt;a href="course/defuse-the-deadlock-sqlchallenge/"&gt;The SQLChallenge&lt;/a&gt; links you to a course which explains more of the background on what deadlocks are, how to capture deadlock graphs, and even more info on how to solve deadlocks &amp;ndash; with a totally different deadlock example.&lt;/p&gt;
&lt;p&gt;Even if you&amp;rsquo;ve never faced off with a deadlock before, you can solve &amp;rsquo;em!&lt;/p&gt;
&lt;h2 id="sqlchallenges-are-now-free"&gt;SQLChallenges are now free&lt;/h2&gt;
&lt;p&gt;Check them &lt;a href="https://kendralittle.com/topics/sqlchallenges/"&gt;all out here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>When Were Statistics Last Updated for a Heap?</title><link>https://kendralittle.com/2018/02/16/when-were-statistics-last-updated-for-a-heap/</link><pubDate>Fri, 16 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/16/when-were-statistics-last-updated-for-a-heap/</guid><description>&lt;p&gt;I got a question last week from a very smart fellow:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How can I tell when statistics were last updated for a heap?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before I could email him back, I soon got another email in which he answered his own question.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying that he&amp;rsquo;s smart because he answered his own question. I&amp;rsquo;m saying he&amp;rsquo;s smart because I&amp;rsquo;ve met him before, and he&amp;rsquo;s a very insightful person and a great problem solver!&lt;/p&gt;
&lt;p&gt;In his later email, he said he was embarrassed about the question. I guess it felt a bit basic. But it&amp;rsquo;s not a dumb question at all.&lt;/p&gt;
&lt;h2 id="i-think-of-this-as-a-framework-type-question"&gt;I think of this as a &amp;ldquo;framework&amp;rdquo; type question&lt;/h2&gt;
&lt;p&gt;When I learn things, I usually first accumulate a bunch of facts that I associate together loosely. When I figure out a question like this, the answer often tends to snap all those facts into a stronger framework than I had before, and I get to a deeper understanding.&lt;/p&gt;
&lt;p&gt;That &lt;em&gt;last&lt;/em&gt; little fact that puts your framework together often feels glaringly obvious afterward. But it certainly didn&amp;rsquo;t before!&lt;/p&gt;
&lt;h2 id="we-think-of-statistics-as-being-for-a-table-in-sql-server"&gt;We think of statistics as being for a table in SQL Server&lt;/h2&gt;
&lt;p&gt;Statistics are little descriptive pieces of information that help the optimizer estimate how data is distributed.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say I&amp;rsquo;m SELECTing StateCode from dbo.Address WHERE AddressId = 420101.&lt;/p&gt;
&lt;p&gt;If dbo.Address has a unique clustered index on AddressId, it will have a statistic associated with the clustered index that helps it understand what AddressIds are present. It also understands that AddressIds are unique, and therefore there&amp;rsquo;s at most only one row for AddressId = 420101.&lt;/p&gt;
&lt;h2 id="but-what-if-dboaddress-was-a-heap"&gt;But what if dbo.Address was a heap?&lt;/h2&gt;
&lt;p&gt;A heap is a table without a clustered index.&lt;/p&gt;
&lt;p&gt;If dbo.Address if dbo.Address was a heap, there wouldn&amp;rsquo;t be a nice unique clustered index with a related statistic to give it this information.&lt;/p&gt;
&lt;p&gt;Instead, a few things could happen when this query ran:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If there is a nonclustered index that leads on the AddressId column, it will have a statistic associated with it. If the nonclustered index is unique, then that uniqueness will be known as well.&lt;/li&gt;
&lt;li&gt;If there is an existing &lt;em&gt;column&lt;/em&gt; statistic, information about the cardinality and data ranges can be used from that&lt;/li&gt;
&lt;li&gt;If no index or column statistic exists and the database allows column statistics to be automatically created (which is a default setting), then a little column statistic can be created.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But notice, no &amp;ldquo;heap&amp;rdquo; statistic will be created.&lt;/p&gt;
&lt;h2 id="there-are-two-types-of-statistics-index-statistics-and-column-statistics"&gt;There are two types of statistics: index statistics and column statistics&lt;/h2&gt;
&lt;p&gt;Although we tend of thinking as statistics as being for a &lt;em&gt;table&lt;/em&gt; (and I tend to have this thought framework as well), this isn&amp;rsquo;t really the case.&lt;/p&gt;
&lt;p&gt;For indexes, statistics describe the data in the key columns of that index. The leading column of the index is particularly well described, as it gets a lot of detail captured about it in a part of the statistic called the histogram.&lt;/p&gt;
&lt;p&gt;Column statistics describe individual columns.&lt;/p&gt;
&lt;p&gt;What would a statistic be if it described a heap? A heap doesn&amp;rsquo;t have key columns. There is no &amp;ldquo;leading&amp;rdquo; column defined, it&amp;rsquo;s simply a table structure without an index.&lt;/p&gt;
&lt;h2 id="so-when-were-statistics-last-updated-for-a-heap"&gt;So: when were statistics last updated for a heap?&lt;/h2&gt;
&lt;p&gt;For a heap, you can look at individual column statistics as well as index statistics and examine which each of them was last updated, with a query like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auto_created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STUFF&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TYPE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NVARCHAR(MAX)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat_cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_temporary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_recompute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modification_counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows_sampled&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_stats_properties&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what the first few columns of the results look like for my heap named dbo.Test:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/heap-statistics-last-updated.png"&gt;
&lt;/figure&gt;
&lt;p&gt;If you&amp;rsquo;d like to build the dbo.Test heap and play around with it, get &lt;a href="https://gist.github.com/LitKnd/4b1a10a503b209f28f027a32e5c09c9a"&gt;code to do so in this Gist&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How I Accidentally Found a Passion for Plants (#TSQL2sDay 99)</title><link>https://kendralittle.com/2018/02/13/how-i-accidentally-found-a-passion-for-plants-tsql2sday/</link><pubDate>Tue, 13 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/13/how-i-accidentally-found-a-passion-for-plants-tsql2sday/</guid><description>&lt;p&gt;For TSQL Tuesday #99, @AaronBertrand gave us an invitation to write about something we’re passionate about outside of SQL Server.&lt;/p&gt;
&lt;p&gt;As a community we spend a lot of time digging into nerdy topics, which is fun, but I think it&amp;rsquo;s interesting to find out what people are involved in.&lt;/p&gt;
&lt;h2 id="i-used-to-think-i-couldnt-grow-plants"&gt;I used to think I couldn&amp;rsquo;t grow plants&lt;/h2&gt;
&lt;p&gt;I went to the kind of college where students often grew plants.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s not a metaphor for growing pot. Quite a lot of my fellow students were into gardening and liked to grow houseplants in the dorm.&lt;/p&gt;
&lt;p&gt;But I couldn&amp;rsquo;t even keep an air-plant alive. (It turns out they don&amp;rsquo;t just live on air. I had no idea.) After a couple of failed attempts at indoor gardening, I gave up.&lt;/p&gt;
&lt;h2 id="i-realized-our-home-was-not-very--lively"&gt;I realized our home was not very &amp;hellip; lively&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/oregano-herb-mug-225x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Last year had some rough personal moments at our house. We had two much-loved elderly cats, and they both passed away over the course of the year from different illnesses.&lt;/p&gt;
&lt;p&gt;Everything felt very empty around the house. Even our dog, Mister, agreed.&lt;/p&gt;
&lt;p&gt;One day I was at a store and saw a set of three succulents on sale. I thought, hey&amp;mdash; maybe caring for a plant could be a good thing?&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t think of it as a replacement for a pet, but honestly we had spent so much time caring for the cats when they were ill that simply having something new to care for seemed like a decent idea.&lt;/p&gt;
&lt;p&gt;Little did I know that about a year later, I would have more than 30 plants.&lt;/p&gt;
&lt;h2 id="luckily-succulents-are-pretty-easy"&gt;Luckily, succulents are pretty easy&lt;/h2&gt;
&lt;p&gt;Like most new plant owners, I over watered the plants at first. Then I under watered them. The succulents put up with it pretty well, and bounced back each time.&lt;/p&gt;
&lt;p&gt;And I found I liked them. &lt;em&gt;I really liked them&lt;/em&gt;. I got interested in learning their names, and I bought a few more succulents. And then I ventured into buying more and more plants.&lt;/p&gt;
&lt;h2 id="things-ive-learned-about-raising-plants-in-no-particular-order"&gt;Things I&amp;rsquo;ve learned about raising plants, in no particular order&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/audrey-the-philodendron-225x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I still make a lot of goofs with my plants, but here&amp;rsquo;s a few things I&amp;rsquo;ve learned&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t blow all your money at Home Depot if you&amp;rsquo;re just starting out. Ikea is a much more affordable source for &lt;a href="http://www.ikea.com/us/en/catalog/categories/departments/decoration/10778/"&gt;inexpensive pots&lt;/a&gt; and &lt;a href="http://www.ikea.com/us/en/catalog/categories/departments/decoration/10779/"&gt;inexpensive live plants&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Local nurseries are not created equal: some are far more affordable than others! Compare prices and look for sales.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t re-pot plants just because. You&amp;rsquo;re usually better off keeping the plants in the pot they come in for a while. To dress the plant up, just buy a pot that fits around the built-in pot.&lt;/li&gt;
&lt;li&gt;Succulents and cacti like different types of soil than moisture loving plants. When you do get to the point where you want to re-pot something, look up what type of soil it does best in before you jump in. (Sorry, jade plant!)&lt;/li&gt;
&lt;li&gt;Different plants need different light levels and amounts of water. It&amp;rsquo;s worth the time to research what your plant is and then look up how dry you should let the soil get. &lt;a href="https://portlandnursery.com/houseplants/houseplants/"&gt;Here is a quick reference guide for houseplants&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="like-a-lot-of-things-the-secret-to-growing-plants-is-persistence"&gt;Like a lot of things, the secret to growing plants is persistence&lt;/h2&gt;
&lt;p&gt;We love going to the restaurant &lt;a href="https://www.nodoguropdx.com"&gt;Nodoguro&lt;/a&gt; here in Portland. We don&amp;rsquo;t eat out a ton these days, but it&amp;rsquo;s our very favorite place and we budget to make it happen as often as we can. We go there enough that we&amp;rsquo;ve met several other regulars.&lt;/p&gt;
&lt;p&gt;At one dinner recently, I got to sit next to a regular who loves growing roses. I&amp;rsquo;m still pretty intimidated by &amp;ldquo;fancy things&amp;rdquo; like outdoor roses, so I asked him a bunch of questions.&lt;/p&gt;
&lt;p&gt;His main piece of advice to me was to start by purchasing one plant, and to think of it as an annual in a way (even if it isn&amp;rsquo;t). He said that it&amp;rsquo;s often important to experiment, and he still sometimes has plants that don&amp;rsquo;t do well. He said that even if you enjoy the plant for just that one season and it doesn&amp;rsquo;t make it, then that&amp;rsquo;s a win.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/summit-2017-swag-planter-225x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Thinking about it this way basically makes it easier to try again. It makes it easier to be persistent.&lt;/p&gt;
&lt;h2 id="plants-are-exciting--in-a-slow-way"&gt;Plants are exciting &amp;hellip; in a slow way&lt;/h2&gt;
&lt;p&gt;I think of my houseplants as interesting friends, in a way. It&amp;rsquo;s not that I think they&amp;rsquo;re people, or pets. They share the space in our home and they contribute &amp;ndash; our home is more green and more fresh now. It&amp;rsquo;s more alive.&lt;/p&gt;
&lt;p&gt;I love wandering around the house, checking on the health of my favorite philodendron, seeing how the spider plant is coming along (I think soon it will be old enough to sprout &amp;ldquo;pups&amp;rdquo;), and looking at the fern which I have very nearly killed four times to see if it may bounce back for real, this time.&lt;/p&gt;
&lt;p&gt;Another thing I learned: ferns aren&amp;rsquo;t all that easy.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not quite to the level of becoming a plant nerd, but I&amp;rsquo;m glad that I discovered that I could develop a green thumb. It turns out, just about anyone can.&lt;/p&gt;
&lt;p&gt;Oh, but another thing I learned: if you start searching for grow lights for your houseplants on Amazon, you start getting all sorts of weird product recommendations, because they too assume that you want to grow marijuana. (I just want my succulents to look fabulous, even in a cloudy Northwest winter.)&lt;/p&gt;</description></item><item><title>Formatting a VTT Caption File into a Transcript with Sublime Text and Multiple Regular Expressions</title><link>https://kendralittle.com/2018/02/08/formatting-a-vtt-caption-file-into-a-transcript-with-sublime-text-and-multiple-regular-expressions/</link><pubDate>Thu, 08 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/08/formatting-a-vtt-caption-file-into-a-transcript-with-sublime-text-and-multiple-regular-expressions/</guid><description>&lt;p&gt;Do you ever need to use a text editor to apply regular expressions to files? If so, this post is for you! If not, you may wanna skip it and just return to it if you ever need it.&lt;/p&gt;
&lt;p&gt;Ever since I started working with data, I&amp;rsquo;ve occasionally had to format raw text files for a variety of reasons. Sometimes it&amp;rsquo;s a one-time import to a database system, or a one-time analysis. Often it&amp;rsquo;s not directly related to a database at all, but it&amp;rsquo;s part of a business process.&lt;/p&gt;
&lt;p&gt;I first learned about regular expressions when formatting a large data file: I needed to remove line endings, and regular expressions were the answer.&lt;/p&gt;
&lt;p&gt;Throughout my career, those regular expressions have come in handy. I need them just often enough that I can usually get the job done after a bunch of missteps and cursing.&lt;/p&gt;
&lt;h2 id="these-days-i-use-a-series-of-regular-expressions-to-format-caption-files-for-my-training-videos"&gt;These days, I use a series of regular expressions to format caption files for my training videos&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s how my workflow works. I use a Mac, and I list the online providers I use in the steps below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I create and edit videos, then upload them to my host (currently Vimeo)&lt;/li&gt;
&lt;li&gt;After the videos are processed and available, I put in an order with my caption provider (currently Rev.com, one of Vimeo&amp;rsquo;s recommended partners for captions) to generate captions for those videos and automatically upload the captions to the video&lt;/li&gt;
&lt;li&gt;After the captions are done, I review the captions in the editor provided by Rev.com. Some of the captions are great, and some of the captions are&amp;hellip; hilariously bad, I suppose depending on who did them. I make corrections in the editor, then press an upload button to update the captions in the video&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of that is human-brain-thinky work, no regular expressions needed.&lt;/p&gt;
&lt;h2 id="heres-the-thing-i-also-want-atranscript-of-the-corrected-work"&gt;Here&amp;rsquo;s the thing: I also want a &lt;em&gt;transcript&lt;/em&gt; of the corrected work&lt;/h2&gt;
&lt;p&gt;Rev.com doesn&amp;rsquo;t make it easy to download a transcript after my edits. I can download a transcript file from the orders page, but it&amp;rsquo;s before all the fixes, and I&amp;rsquo;m not going to do the whole editing process twice.&lt;/p&gt;
&lt;p&gt;I figured out a workaround to download the edited captions quickly, then process the text so it&amp;rsquo;s ready to become a transcript.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click &amp;lsquo;Go to video&amp;rsquo; on the pop-up in Rev.com&lt;/li&gt;
&lt;li&gt;Click the &amp;lsquo;Download&amp;rsquo; button on Vimeo, then &amp;lsquo;Download captions and subtitles&amp;rsquo;. It downloads as a .vtt file (but with a .vtt.txt set of extensions for some reasons)&lt;/li&gt;
&lt;li&gt;Open the caption file in &lt;a href="https://www.sublimetext.com"&gt;Sublime Text 3&lt;/a&gt; on my Mac&lt;/li&gt;
&lt;li&gt;Open the Command Palette (Command + Shift + P on a Mac)&lt;/li&gt;
&lt;li&gt;Select my custom formatter (a sequence I set up with RegReplace to apply a series of regular expressions) and hit enter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voila, my text file is no longer formatted as a VTT file, it is now a block of text!&lt;/p&gt;
&lt;p&gt;From here, I (or an editor, once I get to the point to pass this whole process off to someone else), can add paragraphs and headings to make this a pretty transcript to go below the video.&lt;/p&gt;
&lt;p&gt;The only part of this which takes a while is correcting the goofs in the captions. (Although many of the goofs are funny, they&amp;rsquo;re pretty distracting if you use the captions or try to read the transcript.)&lt;/p&gt;
&lt;h2 id="need-to-set-up-something-similar-heres-the-resources-i-use"&gt;Need to set up something similar? Here&amp;rsquo;s the resources I use&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://www.sublimetext.com"&gt;Sublime Text 3&lt;/a&gt; and get comfy with it&lt;/li&gt;
&lt;li&gt;Install the &lt;a href="https://facelessuser.github.io/RegReplace/"&gt;Reg Replace Sublime Text 3 plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href="https://facelessuser.github.io/RegReplace/usage/"&gt;Reg Replace User Guide&lt;/a&gt; to do two things:
&lt;ol&gt;
&lt;li&gt;Define your replacements in the &lt;em&gt;reg_replace_rules.sublime-settings&lt;/em&gt; file.
&lt;ul&gt;
&lt;li&gt;To open this from Sublime Text 3 in the menus, it is: Sublime Text -&amp;gt; Preferences -&amp;gt; Package Settings -&amp;gt; RegReplace -&amp;gt; Rules - User&lt;/li&gt;
&lt;li&gt;The replacements I&amp;rsquo;m using &lt;a href="https://gist.github.com/LitKnd/5f98f0f0dcbc4e4bc88c10a6ee6717eb"&gt;are here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set up a sequence to call the replacements. I chose to do the method of creating an entry for the Command Palette, because that&amp;rsquo;s one of the few things I know how to use in Sublime Text. This basically means editing the &lt;em&gt;Default.sublime-commands&lt;/em&gt; file.
&lt;ul&gt;
&lt;li&gt;There is probably some way to access this in the menus but&amp;hellip; I have no idea. My file is at /Users/&lt;strong&gt;kendralittle&lt;/strong&gt;/Library/Application Support/Sublime Text 3/Packages/User&lt;/li&gt;
&lt;li&gt;Swap in your username unless you are also a user named kendra little&lt;/li&gt;
&lt;li&gt;The contents of my Default.sublime-commands file &lt;a href="https://gist.github.com/LitKnd/5f98f0f0dcbc4e4bc88c10a6ee6717eb"&gt;are here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The good news is that once you do this, everything is pretty darn fast and you don&amp;rsquo;t have to worry about it much.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s sure a heck of a lot faster than editing the VTT files manually.&lt;/p&gt;</description></item><item><title>Does a Clustered Index Give a Default Ordering?</title><link>https://kendralittle.com/2018/02/02/does-a-clustered-index-give-a-default-ordering/</link><pubDate>Fri, 02 Feb 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/02/02/does-a-clustered-index-give-a-default-ordering/</guid><description>&lt;p&gt;I recently got a great question: if I order by a column where all rows in that column have the same value, will SQL Server then order the results by the clustered index key?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Index-Librarian-badge-400-400.png"
alt="Index-Librarian" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="the-short-answersql-server-only-guarantees-that-results-are-ordered-per-the-columns-you-specify-in-an-order-by-clause"&gt;The short answer: SQL Server only guarantees that results are ordered per the columns you specify in an ORDER BY clause&lt;/h2&gt;
&lt;p&gt;There is no &amp;ldquo;default&amp;rdquo; ordering that a query will fall back on outside of an ORDER BY clause.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Results may come back in the order of the clustered index, or they may not&lt;/li&gt;
&lt;li&gt;Even if results come back in the order of the clustered index on one run of the query, they may not come back in the same order if you run it again&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need results to come back in a specific order, you must be explicit about it in the ORDER BY clause of the query.&lt;/p&gt;
&lt;p&gt;Bonus details: ORDER BY is special inside view definitions. As &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql"&gt;Books Online explains&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The ORDER BY clause is used only to determine the rows that are returned by the TOP or OFFSET clause in the view definition. The ORDER BY clause does not guarantee ordered results when the view is queried, unless ORDER BY is also specified in the query itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The question wasn&amp;rsquo;t about views, though, it was about queries.&lt;/p&gt;
&lt;h2 id="lets-prove-it-bring-on-the-demo"&gt;Let&amp;rsquo;s prove it! Bring on the demo&lt;/h2&gt;
&lt;p&gt;The question came with some demo code. For fun, I adapted the code to use 1 million results in the demo table, which introduces the extra factor of parallelism on my test instance. (I have the Cost Threshold for Parallelism setting at the default of 5, which is super low&amp;ndash; I have it that way just for demo purposes.)&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to play along, the sample code for this is in &lt;a href="https://gist.github.com/LitKnd/8c6a031b236764a0d91893219265347a"&gt;a Gist&lt;/a&gt;, which I&amp;rsquo;ve also included at the bottom of this post.&lt;/p&gt;
&lt;h2 id="our-table"&gt;Our table&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbo.Test-schema.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Our demo table has a simple schema: there are three columns. The column named Id is a clustered primary key.&lt;/p&gt;
&lt;p&gt;If we do a simple unordered SELECT statement from the table, the results &lt;em&gt;look&lt;/em&gt; like SQL Server will default to returning the rows to us in an order defined by the clustered primary key.&lt;/p&gt;
&lt;p&gt;However, that just &lt;em&gt;happened&lt;/em&gt; to be what we got this time. We can&amp;rsquo;t rely on that in other queries, as we&amp;rsquo;re going to see.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbo-test-example-data-350x350.png"
alt="Example data from dbo.Test"&gt;
&lt;/figure&gt;
&lt;h2 id="query-1---order-by-extra-desc"&gt;Query 1 - Order by Extra, DESC&lt;/h2&gt;
&lt;p&gt;Notice in our sample data that the &amp;ldquo;Extra&amp;rdquo; column is an integer which always has the value 555. That is true for every row in the table.&lt;/p&gt;
&lt;p&gt;What happens if we order by &amp;ldquo;Extra&amp;rdquo;? All the rows have the same value. Will SQL Server &amp;ldquo;fall back&amp;rdquo; on ordering by the Clustered Index&amp;ndash; which is the only index it has?&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-1-results.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Nope! Id = 1 is nowhere in sight.&lt;/p&gt;
&lt;p&gt;And to make this &lt;em&gt;really&lt;/em&gt; fun, run the exact same query a second time. Here&amp;rsquo;s what I got on my second run:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-1-second-run-results.png"&gt;
&lt;/figure&gt;
]&lt;/p&gt;
&lt;p&gt;The ordering is different. None of the data has changed in the table, I just happened to get the rows back in a different order.&lt;/p&gt;
&lt;h2 id="lets-look-into-the-execution-plan"&gt;Let&amp;rsquo;s look into the execution plan&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the plan I got for Query 1:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-1-execution-plan.png"&gt;
&lt;/figure&gt;
]&lt;/p&gt;
&lt;p&gt;This query got parallelism on my test instance. It did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An unordered scan on the clustered index, separating the work cross multiple threads&lt;/li&gt;
&lt;li&gt;A sort on the Extra column (no other columns to sort by)&lt;/li&gt;
&lt;li&gt;A re-gathering of the threads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SQL Server is trying to get the results back to me as quickly as possible. It is only sorting things by the Extra column, and since that value is the same for all rows in this case, I can get rows back in whatever order happens first on that run.&lt;/p&gt;
&lt;h2 id="query-2---what-if-we-add-in-top-2"&gt;Query 2 - What if we add in TOP 2?&lt;/h2&gt;
&lt;p&gt;For query 2, you&amp;rsquo;ll get back two rows. But because the only column specified in the ORDER BY is Extra (and all rows for Extra have the same value), if you run the query repeatedly you will likely see that you don&amp;rsquo;t always get the &lt;em&gt;same&lt;/em&gt; two rows back (and they aren&amp;rsquo;t the rows for Id = 1 and Id = 2).&lt;/p&gt;
&lt;p&gt;The TOP does change the execution plan, in this case.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-2-execution-plan-with-details-1024x407.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Why do I have both a Top N Sort and then another Top?&lt;/p&gt;
&lt;p&gt;Well, I have 4 cores on this instance, and the query is going parallel. What it&amp;rsquo;s doing is scanning the clustered index with 4 cores. For each of those cores, it gets the top 2 rows (based on Extra), then it pulls those 8 rows together and does a final TOP on them.&lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;m only ordering by the column Extra, SQL Server doesn&amp;rsquo;t consider anything else again.&lt;/p&gt;
&lt;h2 id="query-3---offset-and-fetch"&gt;Query 3 - OFFSET and FETCH&lt;/h2&gt;
&lt;p&gt;Query gets rid of TOP, and instead tries out OFFSET and FETCH.&lt;/p&gt;
&lt;p&gt;Again, we get two rows back (because of the FETCH limitation), but they can be any two rows in the table since our ORDER BY column is essentially meaningless (all rows have the same value).&lt;/p&gt;
&lt;p&gt;I get the exact same plan as I got for the TOP query in this case&amp;ndash; same costs, same estimates, everything.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-3-offset-and-fetch-1024x371.png"&gt;
&lt;/figure&gt;
]&lt;/p&gt;
&lt;h2 id="query-4---offset-and-fetch-with-local-variables"&gt;Query 4 - OFFSET and FETCH with local variables&lt;/h2&gt;
&lt;p&gt;Query 4 gets a little fancier &amp;ndash; instead of using literal values for offset and fetch, it introduces local variables. Again, we get two rows back, but they can be any two rows in the table.&lt;/p&gt;
&lt;p&gt;But the execution plan is different:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-4-offset-fetch-local-variables-1024x564.png"&gt;
&lt;/figure&gt;
&lt;p&gt;We don&amp;rsquo;t have an estimate of 8 rows anymore&amp;ndash; we have an estimate of 100.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because we used a local variable, @PageSize. Local variables anonymize their contents, unless you use a RECOMPILE hint. When SQL Server optimized this query, it wasn&amp;rsquo;t sure how many rows it needed to fetch, so it just guessed. If you set @PageSize = 200000, you&amp;rsquo;ll get the exact same estimates and plan for this query.&lt;/p&gt;
&lt;h2 id="is-it-only-parallelism-that-can-cause-this"&gt;Is it only parallelism that can cause this?&lt;/h2&gt;
&lt;p&gt;Nope, there are other things, such as allocation order scans, which might change up the order, too.&lt;/p&gt;
&lt;h2 id="tldr-when-it-comes-to-ordering-of-results-sql-server-does-what-you-ask-in-an-order-by-and-no-more"&gt;tldr: When it comes to ordering of results, SQL Server does what you ask in an ORDER BY&amp;ndash; and no more!&lt;/h2&gt;
&lt;p&gt;Except in the case of ORDER BY inside a view, when it actually does &lt;em&gt;less&lt;/em&gt;. (Details back at the top of the post.)&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not convinced after all this, or just need a laugh, &lt;a href="http://michaeljswart.com/2013/09/without-order-by-you-cant-depend-on-the-order-of-results/"&gt;read Michael Swart&amp;rsquo;s impressions of bloggers answering a similar question&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="and-heres-that-demo-code"&gt;And here&amp;rsquo;s that demo code&amp;hellip;&lt;/h2&gt;
&lt;script src="https://gist.github.com/LitKnd/8c6a031b236764a0d91893219265347a.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/8c6a031b236764a0d91893219265347a"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>Watch my live session: When Partitioning Indexes Hurts Performance (and How to Fix It)</title><link>https://kendralittle.com/2018/01/25/watch-my-live-session-when-partitioning-indexes-hurts-performance-and-how-to-fix-it/</link><pubDate>Thu, 25 Jan 2018 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2018/01/25/watch-my-live-session-when-partitioning-indexes-hurts-performance-and-how-to-fix-it/</guid><description>&lt;p&gt;I&amp;rsquo;m very that my session on table partitioning from the 2017 SQL PASS Summit is being &lt;a href="http://www.pass.org/summit/2018/Sessions/BestOfSummit.aspx"&gt;featured as one of the &amp;ldquo;Best of Summit&amp;rdquo; videos.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I had a terrific time presenting this session, thanks to everyone in the audience: you were awesome!&lt;/p&gt;
&lt;p&gt;You can watch the video here, and follow the link above to see even more great videos from the conference for free.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/daXhoZNhbW0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="technical-notes"&gt;Technical notes&lt;/h2&gt;
&lt;p&gt;Around 26 minutes in, I&amp;rsquo;m talking about hash match operators and I mention tempdb. &lt;a href="https://twitter.com/Hugo_Kornelis"&gt;Hugo Korneilis&lt;/a&gt; pointed out on Twitter that hash matches don&amp;rsquo;t always spill to tempdb. That&amp;rsquo;s totally correct&amp;ndash; I should have said that this happens on a memory scratch pad that &lt;em&gt;may&lt;/em&gt; spill to a place called tempdb.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about spills, &lt;a href="http://rusanu.com/2011/10/19/understanding-hash-sort-and-exchange-spill-events/"&gt;here is a good article by Remus Rusanu on the topic&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="scripts"&gt;Scripts&lt;/h2&gt;
&lt;script src="https://gist.github.com/LitKnd/025086682932cb3666e260b5b7499df0.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/025086682932cb3666e260b5b7499df0"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>Watch the first lesson in my new Repeatable Read and Serializable Isolation Levels course! (Video with transcript and captions)</title><link>https://kendralittle.com/2017/12/18/watch-the-first-lesson-in-my-new-repeatable-read-and-serializable-isolation-levels-course-video-with-transcript-and-captions/</link><pubDate>Mon, 18 Dec 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/12/18/watch-the-first-lesson-in-my-new-repeatable-read-and-serializable-isolation-levels-course-video-with-transcript-and-captions/</guid><description>&lt;p&gt;Woo hoo! I&amp;rsquo;ve just added a new course: &lt;a href="https://kendralittle.com/course/repeatable-read-and-serializable-isolation-levels-45-minutes/"&gt;Repeatable Read and Serializable Isolation Levels in SQL Server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: even better news&amp;hellip; courses are now open and free for all&lt;/em&gt; :smile:&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Repeatable-Read-and-Serializable-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s the scoop on what &lt;a href=""&gt;the course&lt;/a&gt; covers&amp;hellip;&lt;/p&gt;
&lt;p&gt;Serializable and Repeatable Read isolation levels offer protections so your users won’t see weird or incorrect data — but there are tradeoffs for those protections. Learn how to tell if your existing applications are using these types of isolation levels, when you might want to raise your isolation level in SQL Server, and the tradeoffs you make if you choose serializable or repeatable read with disk-based tables.&lt;/p&gt;
&lt;p&gt;This course includes 47 minutes of videos, plus a quiz:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why do we have repeatable read and serializable? (10 minutes)&lt;/li&gt;
&lt;li&gt;Course downloads: scripts and slides (PDF)&lt;/li&gt;
&lt;li&gt;Demo: Give me correct data or give me death (15 minutes)&lt;/li&gt;
&lt;li&gt;Animated play diagram of the index intersection problem (6 minutes)&lt;/li&gt;
&lt;li&gt;How you can get serializable isolation, even if you didn’t ask for it (4 minutes)&lt;/li&gt;
&lt;li&gt;How to tell if apps are using repeatable read or serializable (5 minutes)&lt;/li&gt;
&lt;li&gt;What’s the best way to get correct data? (7 minutes)&lt;/li&gt;
&lt;li&gt;Course quiz (10 questions)&lt;/li&gt;
&lt;li&gt;Course survey (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note sure if this course is for you? Watch the first lesson right now, below &amp;ndash; it&amp;rsquo;s 10 minutes long, and it covers important problems that you need to know about the default read committed isolation level in SQL Server.&lt;/p&gt;
&lt;h2 id="why-do-we-have-repeatable-read-and-serializable-10-minutes"&gt;Why do we have repeatable read and serializable? (10 minutes)&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/xR70UlE_xbo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h1 id="transcript"&gt;Transcript&lt;/h1&gt;
&lt;p&gt;Welcome to Repeatable Read and Serializable Isolation Levels in SQL Server. I&amp;rsquo;m Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;p&gt;Today, we will be answering five questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We&amp;rsquo;ll be talking about why we need repeatable read and serializable isolation levels; we&amp;rsquo;ll be doing demos of how we can get incorrect data in the read committed isolation level&lt;/li&gt;
&lt;li&gt;If we&amp;rsquo;re using repeatable read and serializable, under different situations we say we have to have correct data or we&amp;rsquo;re just not going to finish our query&lt;/li&gt;
&lt;li&gt;We will talk about ways that the serializable isolation level may sneak in, even if you aren&amp;rsquo;t using it on purpose! Even if you if you haven&amp;rsquo;t changed your isolation level to serializable, or use a hint, there&amp;rsquo;s some scenarios where SQL Server will escalate your isolation levels behind-the-scenes.&lt;/li&gt;
&lt;li&gt;And we&amp;rsquo;ll talk about how to tell if your apps are even using these &amp;ndash; as well as a very important question:&lt;/li&gt;
&lt;li&gt;What&amp;rsquo;s the way to make sure that you get correct data in SQL Server?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="first-up-why-do-we-need-repeatable-read-and-serializable"&gt;First up: why do we need repeatable read and serializable?&lt;/h2&gt;
&lt;p&gt;In fact there can be clowns and ghosts &amp;ndash; or phantoms&amp;ndash; that are sneaking into your data!&lt;/p&gt;
&lt;p&gt;The default isolation level in SQL Server is called read committed. This is the default isolation level in what&amp;rsquo;s called the &amp;ldquo;boxed product&amp;rdquo; of SQL Server. If you install SQL Server yourself in a virtual machine or on a server&amp;ndash; I&amp;rsquo;m not talking about Azure SQL Database&amp;ndash; but if you create a database on a SQL Server you install yourself, the default isolation for your queries is called read committed. In Azure SQL Database, it&amp;rsquo;s different, because read committed has some issues.&lt;/p&gt;
&lt;h2 id="read-committed-sounds-really-good-right"&gt;&amp;ldquo;Read committed&amp;rdquo; sounds really good, right?&lt;/h2&gt;
&lt;p&gt;Okay, I&amp;rsquo;m going to read committed data. That sounds like it would be great, but read committed is lock based.&lt;/p&gt;
&lt;p&gt;When we read, say from an index in read committed, we run through that index getting locks as we go and releasing them right away. That also sounds good, but when you look into the details, what this means is: since we let go of the locks as soon as we read them, and our query may still be running, data can move around on us.&lt;/p&gt;
&lt;p&gt;We may read some rows twice: if we read it and passed it and then it jumped ahead, we may see it again.&lt;/p&gt;
&lt;p&gt;We may miss a row entirely: if I&amp;rsquo;m running through the data and a row is updated and moves behind me, I may never see it as I traverse that index.&lt;/p&gt;
&lt;p&gt;And, we even can return combinations of data that never existed. Just plain part &amp;ldquo;before data&amp;rdquo;, part &amp;ldquo;after data.&amp;rdquo; And we&amp;rsquo;ll dig into this last one. It&amp;rsquo;s the weirdest one, we will dig into a demo in detail and see how that can happen in read committed.&lt;/p&gt;
&lt;h2 id="isolation-levels-are-defined-by-phenomena"&gt;Isolation levels are defined by &amp;ldquo;phenomena&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;When we talk about isolation levels, not just in SQL Server, but when it comes to relational databases altogether, isolation levels are actually defined by what phenomena can happen in that isolation level.&lt;/p&gt;
&lt;p&gt;These phenomena are different types of weirdness that can happen&amp;ndash; different &amp;ldquo;issues&amp;rdquo; if you will that can happen under that isolation level.&lt;/p&gt;
&lt;h3 id="dirty-reads"&gt;Dirty reads&lt;/h3&gt;
&lt;p&gt;Under the default isolation level of read committed, the phenomena of dirty reads&amp;hellip; Represented here by the poop emoji&amp;hellip; that is not possible. So read committed at least has the virtue of not allowing the dirty reads phenomenon.&lt;/p&gt;
&lt;p&gt;But there are other phenomena that can happen in read committed: we can have non repeatable reads, which we will see as a clown. And we can have phantom reads.&lt;/p&gt;
&lt;h3 id="non-repeatable-reads"&gt;Non-repeatable reads&lt;/h3&gt;
&lt;p&gt;The name, at first didn&amp;rsquo;t make any sense to me. But it really means what it says.&lt;/p&gt;
&lt;p&gt;It means: I read this data and if in my transaction I were to read it again, I would not get the same value. This can be a huge problem, and the data will just look wront to users.&lt;/p&gt;
&lt;h3 id="phantom-reads-are-a-little-different"&gt;Phantom reads are a little different&lt;/h3&gt;
&lt;p&gt;If I read the same set of rows again, I won&amp;rsquo;t get the same set. Maybe there is a row inserted, maybe there were three rows when I read the data first, maybe there were four rows one I read the data again. Nothing was &lt;em&gt;updated&lt;/em&gt;, but a phantom row appeared.&lt;/p&gt;
&lt;h2 id="simple-examples-of-non-repeatable-reads-and-phantom-reads"&gt;Simple examples of non-repeatable reads and phantom reads&lt;/h2&gt;
&lt;p&gt;This is not that hard to imagine.&lt;/p&gt;
&lt;h3 id="for-a-non-repeatable-read-imagine-that-im-running-a-report"&gt;For a non-repeatable read, imagine that I&amp;rsquo;m running a report&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m running this in read committed, and I do begin tran. My first SQL statement selects the SUM of my revenue from the table. I&amp;rsquo;ve summed up my revenue. After that first statement completes, another transaction updates a row in that table, and it changes some of the data. My report it has the summary data at the top, and it has a detail section below it. So I then run a statement that&amp;rsquo;s getting all the detail data. In read committed we are going to get the updated information in that second query. So, when we selected the sum of revenuel we have a non repeatable read in there. We read some data that changed after that. We read it again and it was different.&lt;/p&gt;
&lt;h3 id="phantom-rows-are-similar-were-running-our-same-report"&gt;Phantom rows are similar. We&amp;rsquo;re running our same report.&lt;/h3&gt;
&lt;p&gt;We select our summary data, and then after we select that summary data, but before we do anything else, another transaction along. They insert a new row into the same data we&amp;rsquo;re selecting. In this case we don&amp;rsquo;t even have a where clause, we don&amp;rsquo;t even have any predicates. They just insert a row into that table.&lt;/p&gt;
&lt;p&gt;Now, when we run the detail data, now we&amp;rsquo;ve got an extra row in there that isn&amp;rsquo;t accounted for in our sum.&lt;/p&gt;
&lt;h3 id="this-data-isnt-right"&gt;This data isn&amp;rsquo;t right&lt;/h3&gt;
&lt;p&gt;In both of these cases, in the case of the non-repeatable read and in the case of the phantom read, if your CEO is reading this report, she&amp;rsquo;s going to look at this and be like, &amp;ldquo;This data isn&amp;rsquo;t right. These numbers don&amp;rsquo;t match.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So, we either look like a clown, or we&amp;rsquo;re seeing a ghost in our records, neither of which are good.&lt;/p&gt;
&lt;h2 id="higher-isolation-can-protect-you-from-clowns-and-ghosts"&gt;Higher isolation can protect you from clowns and ghosts&lt;/h2&gt;
&lt;p&gt;The isolation levels repeatable read and serializable were introduced to make sure that if we don&amp;rsquo;t want to have these phenomenon, if we don&amp;rsquo;t have these issues, we don&amp;rsquo;t have to. We can prevent them. If we aren&amp;rsquo;t worried about phantoms and we only want to prevent non-repeatable reads, we can set our isolation level to repeatable read. You can also use a query hint, but this as for my entire session, for everything right, you know, I want to use repeatable read unless I hint otherwise. We start our report, we select the SUM of our revenue.&lt;/p&gt;
&lt;p&gt;The difference is, now that I&amp;rsquo;m in repeatable read, I am, after I select this data, I going to hold on to some locks on that data that protects it and says if anyone comes in and they try to update a row, I have a transaction that is &amp;ndash; if I read this data again, it needs to be the same. I need to protect it. So while my transaction is ongoing, somebody else comes in and tries update that row. They are going to be blocked, and they can&amp;rsquo;t read until I&amp;rsquo;m done, until I commit my transaction or roll it back.&lt;/p&gt;
&lt;p&gt;So now, when I select my detail data, my read are repeatable, they are all the same.&lt;/p&gt;
&lt;p&gt;My CEO sees data that matches. I do not look like a clown.&lt;/p&gt;
&lt;p&gt;This is good, right?&lt;/p&gt;
&lt;h2 id="but-there-was-an-impact-there-was-a-tradeoff"&gt;But there was an impact. There was a tradeoff.&lt;/h2&gt;
&lt;p&gt;That transaction that came in to update a row, it was blocked, and it had to wait.&lt;/p&gt;
&lt;p&gt;What happens if in the rest of this transaction I&amp;rsquo;m doing stuff that takes a whole lot of time? And, what if the update is really important and there&amp;rsquo;s an executive from one of my clients waiting for that update to complete on a screen?&lt;/p&gt;
&lt;p&gt;So, there are tradeoffs here, if we&amp;rsquo;re using this method to make sure our data is correct.&lt;/p&gt;
&lt;p&gt;Because if we are using a disk-based table, repeatable read is going to protect this with locks. And with locks can come blocking.&lt;/p&gt;
&lt;p&gt;What if I&amp;rsquo;m worried about inserts? Well, repeatable read isolation level is holding locks on what I read: it isn&amp;rsquo;t doing anything to prevent against rows being inserted. If I&amp;rsquo;m worried about those phantom rows, I need to set my transaction isolation level to serializable.&lt;/p&gt;
&lt;p&gt;Serializable says: you won&amp;rsquo;t have any non-repeatable reads, and you won&amp;rsquo;t have any phantoms. So it includes the protections of repeatable read, and then adds additional protections. In this case, I run my first query and I acquire key range locks that are held to the end of my transaction. I&amp;rsquo;m not just protecting exactly what I&amp;rsquo;ve read, but I&amp;rsquo;m protecting a range that says&amp;ndash; new stuff cannot be inserted into this range. If an insert happens, the insert will be blocked. Same thing for an update, if an update happens it will be blocked. So when I run my last statement, I can get data consistent with the first statement.&lt;/p&gt;
&lt;p&gt;But again, this is a pessimistic&amp;ndash; what we&amp;rsquo;re talking about with repeatable read and serializable are pessimistic isolation levels. We&amp;rsquo;re collecting key range locks, and, our tradeoff is blocking.&lt;/p&gt;
&lt;h2 id="but-we-get-correct-data"&gt;But we get correct data!&lt;/h2&gt;
&lt;p&gt;And that is a good thing!&lt;/p&gt;
&lt;p&gt;Check out the full course (now totally free): &lt;a href="https://kendralittle.com/course/repeatable-read-and-serializable-isolation-levels-45-minutes/"&gt;Repeatable Read and Serializable Isolation Levels in SQL Server&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>New Course: Indexing for Windowing Functions (with preview lesson)</title><link>https://kendralittle.com/2017/12/11/new-course-indexing-for-windowing-functions-with-preview-lessonhttps-sqlworkbooks-com-shop-online-sql-server-video-training-indexing-for-window-functions/</link><pubDate>Mon, 11 Dec 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/12/11/new-course-indexing-for-windowing-functions-with-preview-lessonhttps-sqlworkbooks-com-shop-online-sql-server-video-training-indexing-for-window-functions/</guid><description>&lt;p&gt;I&amp;rsquo;ve just added a fresh new course: &lt;a href="https://kendralittle.com/course/indexing-for-windowing-functions/"&gt;Indexing for Windowing Functions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the rundown:&lt;/p&gt;
&lt;p&gt;Windowing functions give you great flexibility for analyzing data in SQL Server. But how can you get the best performance for your windowing functions?&lt;/p&gt;
&lt;p&gt;In this 45 minute, demo-packed course, you will learn index design for windowing functions, when batch mode may be important, and how to compare the performance of Window Spool and Window Aggregate operators.&lt;/p&gt;
&lt;p&gt;Course lessons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Meet the challenge code (9 minutes)&lt;/li&gt;
&lt;li&gt;Scripts and slide downloads&lt;/li&gt;
&lt;li&gt;Dig into the plan and test a nonclustered index (11 minutes)&lt;/li&gt;
&lt;li&gt;What can an indexed view do? (5 minutes)&lt;/li&gt;
&lt;li&gt;Bring in the nonclustered columnstore index! (8 minutes)&lt;/li&gt;
&lt;li&gt;Hacking in the Window Aggregate operator with a rowstore nonclustered index (9 minutes)&lt;/li&gt;
&lt;li&gt;Summary and recap (4 minutes)&lt;/li&gt;
&lt;li&gt;Quiz: check in on what you learned&lt;/li&gt;
&lt;li&gt;Course survey&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Register for the course here, it&amp;rsquo;s currently free! &lt;em&gt;Sorry, this giveaway has ended.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="preview-the-first-lesson"&gt;Preview the first lesson!&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/BgxpH6jBs58?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;This video has captions you may enable in the viewer, plus a written transcript below.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Learn what we&amp;rsquo;ll cover in this course, then dive into the sample windowing function that we&amp;rsquo;ll be tuning.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Indexing-for-Window-Functions-youtube-300x167.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;That&amp;rsquo;s a happy little window aggregate operator&amp;rdquo; &amp;hellip; Bob Ross&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="welcome-to-indexing-for-window-functions-in-sql-server"&gt;Welcome to Indexing for Window Functions in SQL Server&lt;/h2&gt;
&lt;p&gt;Today we are going to cover: a quick overview of what window functions are, and then we&amp;rsquo;ll spend most of our time today demonstrating how to tune a specific window function. I have an example where we can tune it in all sorts of different ways: with rowstore indexes, with an indexed view, with columnstore indexes. And it gets &amp;ndash; I think &amp;ndash; really interesting!&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re going to spend most of our time tuning that windowing function, then we&amp;rsquo;ll do a recap of the techniques we used and see how are they all turned out. Then we&amp;rsquo;ll finish up with some Q &amp;amp; A. Before we dig into this: some quick concepts.&lt;/p&gt;
&lt;h2 id="when-i-say-window-function-what-do-i-mean"&gt;When I say &amp;lsquo;window function&amp;rsquo; what do I mean?&lt;/h2&gt;
&lt;p&gt;The terms for this are getting kinda interesting. In Books Online, they do use the term &amp;lsquo;windowing functions&amp;rsquo;. The term &amp;lsquo;windowing function&amp;rsquo; isn&amp;rsquo;t just specific to SQL Server. There are other database engines where people use these&amp;ndash; where they talk about windowing functions too.&lt;/p&gt;
&lt;p&gt;What we&amp;rsquo;re talking about when we talk about windowing functions is: looking at a row in the context of a window of data. If I want to do something like row numbering &amp;ndash; okay I want to number my rows, and maybe I want to do a windowed row number. Maybe I want number a set of rows in a group, right? And then restart my numbering for another group. Maybe I want to do a running total: what is the total of this in the context of another set of rows? Like the sum of revenue this quarter, and then the sum of revenue year- to-date.&lt;/p&gt;
&lt;p&gt;Maybe I want to do something like lag and lead: I want to see okay what&amp;rsquo;s this row, and then what was this value for the previous row, or for the next? We can do a lot of these cool things with window functions in SQL Server.&lt;/p&gt;
&lt;h2 id="heres-the-window-function-were-going-to-be-looking-at-today-in-our-demo"&gt;Here&amp;rsquo;s the window function we&amp;rsquo;re going to be looking at today in our demo&lt;/h2&gt;
&lt;p&gt;We will be seeing a lot of this code and I want to talk about it a little bit in screenshots, because I can very easily literally highlight the code. This isn&amp;rsquo;t the whole query we&amp;rsquo;re looking at here.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s two common table expressions at the beginning. The first one is called RunningTotal. What we&amp;rsquo;re doing in that first CTE named RunningTotal is: I&amp;rsquo;m saying okay I want the FirstNameId , you know, given the first name &amp;ndash; I want the state it&amp;rsquo;s in, the Gender for that FirstNameId, and the ReportYear. Then I want to sum up the name count &amp;ndash; OVER &amp;ndash; then we get into the guts of our window function. When I say &amp;lsquo;partition by&amp;rsquo;, what we&amp;rsquo;re doing is we&amp;rsquo;re breaking the data into groups. I want to group by the FirstNameId, the StateCode, and gender.&lt;/p&gt;
&lt;p&gt;&amp;lsquo;Partition&amp;rsquo; is a little confusing here. We&amp;rsquo;re NOT talking about table partitioning! This is specific to the windowing function. That &amp;lsquo;over&amp;rsquo; keyword right before partition is introducing: okay I&amp;rsquo;m summing up name count over groups of the FirstNameId, StateCode, and Gender, and I&amp;rsquo;m ordering by ReportYear. That is my TotalNamed column.&lt;/p&gt;
&lt;p&gt;That first CTE builds my running total. After that we have a second CTE and I have a second windowing function in it: RunningTotalPlusLag is the name of this second CTE, and it&amp;rsquo;s pulling from RunningTotal. RunningTotal itself: you look at the &amp;lsquo;FROM&amp;rsquo; in there, it&amp;rsquo;s pulling from a table named agg.FirstNameByYearState.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re accessing the table in the first CTE. In the second CTE, we&amp;rsquo;re actually accessing RunningTotal, because I want to say: ok, how many were, based on that group of FirstNameId, StateCode, and Gender, how many total had that name the year before? Right? So what I&amp;rsquo;m doing with my running total, is what I want to know is&amp;ndash; when the total amount of FirstNames get that name based on their FirstNameId, StateCode and Gender. Because I don&amp;rsquo;t want to, you know, sum up all the names for all the Chris&amp;rsquo;s who are both male and female. I want to keep the baby names separate.&lt;/p&gt;
&lt;p&gt;But I want to keep track of: Okay, what was their total this year and the previous year. Because our query is going to look at, when did they cross a given threshold? When were more than x number of babies; when did they get this name, based on FirstNameId, StateCode, and Gender, and ReportYear.&lt;/p&gt;
&lt;p&gt;See how I&amp;rsquo;m ordering by ReportYear.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m using my window functions in a fun way here, and what we&amp;rsquo;re looking at is breakthrough values: when did a name break through getting, you know, this x number of babies given this name, based on that windowing function.&lt;/p&gt;
&lt;h2 id="demo-time-lets-dig-in-and-see-how-we-can-tune-this"&gt;Demo Time: Let&amp;rsquo;s dig in and see how we can tune this!&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re asking a lot of this windowing function. Not am I doing a running total, right, but I want to look at the running total for this year AND the previous year altogether. Wo here is our code that we saw in the setup slides. I&amp;rsquo;m just going to highlight it. So, we&amp;rsquo;ve got RunningTotal, our CTE with that running total in it, we&amp;rsquo;ve RunningTotalPlusLag, that says okay what was the running total for the prior year. And here&amp;rsquo;s the guts of our query: this is not pretty TSQL, and that&amp;rsquo;s on purpose, because in the real-world we don&amp;rsquo;t always get to deal pretty TSQL!&lt;/p&gt;
&lt;p&gt;What we&amp;rsquo;re saying in the guts of this is, all right we want the data from RunningTotalPlusLag, because it has TotalNamed, it has everything we want. It has the lag information as well as the running total. We want that data, we&amp;rsquo;re going to join to ref.FirstName where we can actually translate out and see: what are the names. We&amp;rsquo;ve got some predicates in here. We&amp;rsquo;re passing in a threshold parameters, so if the threshold parameter is null, then we&amp;rsquo;re going to say, okay, we&amp;rsquo;re going to set a threshold of one hundred.&lt;/p&gt;
&lt;p&gt;So if you don&amp;rsquo;t pass in a threshold, we&amp;rsquo;ll just assume okay when did the running total get past the one hundred babies, with that name, for that gender, in that state, for that year. Or what year did they pass that value in. Or if threshold isn&amp;rsquo;t null, then we&amp;rsquo;ll take the threshold that&amp;rsquo;s passed in and use that one, right? We do allow a threshold to be null, and then we kinda handle it. And this is where we&amp;rsquo;re saying: okay, we&amp;rsquo;re looking at the running total and then saying, okay in the previous year they had less than that amount, and then they passed that amount in the current year.&lt;/p&gt;
&lt;p&gt;So TotalNamed less than our threshold. Let&amp;rsquo;s go ahead and create our procedure there we now have the PopularNames procedure created. I have not indexed this yet. We are going to give this a first-run, and let me actually turn on my actual execution plans with this button here. We&amp;rsquo;re going to turn our actual plans and give this a first-run.&lt;/p&gt;
&lt;h2 id="the-table-were-pulling-from-is-aggfirstnamebyyearstate"&gt;The table we&amp;rsquo;re pulling from is agg.FirstNameByYearState&lt;/h2&gt;
&lt;p&gt;It has a clustered primary key on it, it does not have any non clustered indexes, nothing tuned for this window function yet. So we&amp;rsquo;re going to get our baseline here, which as you can see is NOT that fast.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t a huge table!&lt;/p&gt;
&lt;p&gt;But, we&amp;rsquo;re having too, for every version mit in the table do a running total based on the FirstNameId, Gender andStateCode. And, then looking at it by each year, ordering by year, and then figuring out: okay when did they pass getting five hundred names (as their running total)?&lt;/p&gt;
&lt;p&gt;For that FirstName and StateCode. For example, here&amp;rsquo;s Tristan. In Arkansas, for males named tristan, it was 2015. In 2014, there were four hundred ninety two Tristans, and in 2015 there were five hundred five. This is, for 2015 in Arkansas, this is the set of names, you know, that passed that threshold that year.&lt;/p&gt;</description></item><item><title>New free webcasts! How keys &amp; includes work, dirty secrets of NOLOCK, and more</title><link>https://kendralittle.com/2017/12/06/new-free-webcasts-how-keys-includes-work-dirty-secrets-of-nolock-and-more/</link><pubDate>Wed, 06 Dec 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/12/06/new-free-webcasts-how-keys-includes-work-dirty-secrets-of-nolock-and-more/</guid><description>&lt;p&gt;As we count down to the end of 2017, I&amp;rsquo;ve just scheduled a fresh batch of free, live webinars for 2018! Join me on Thursdays at 9 am Pacific / noon Eastern / 4 PM UTC.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/free-webcasts-sqlworkbooks-20170627-1.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I would love for you to join me! Your questions and comments make it all worthwhile.&lt;/p&gt;
&lt;h2 id="dec-7---indexing-for-windowing-functions"&gt;Dec 7 - Indexing for Windowing Functions&lt;/h2&gt;
&lt;p&gt;Windowing functions give you great flexibility for analyzing data. But how can you get the best performance for your window functions? Learn about index design for windowing functions, and when batch mode may make a big difference for your query performance.&lt;/p&gt;
&lt;h2 id="dec-14---serializable--repeatable-read"&gt;Dec 14 - Serializable &amp;amp; Repeatable Read&lt;/h2&gt;
&lt;p&gt;Serializable and Repeatable Read isolation levels offer protections so that your users won’t see weird or incorrect data &amp;ndash; and they do this by using specific lock types and lock durations. Learn about how these lock types work against disk-based rowstore tables, how long the locks are held, how to tell if your existing applications are using these types of isolation levels, and when you might want to raise your isolation level in SQL Server.&lt;/p&gt;
&lt;h2 id="2018-webcasts-woot"&gt;2018 Webcasts! WOOT!&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;In 2018, I&amp;rsquo;ll do 45 minute free webcasts every other week&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="jan-11---how-keys-and-included-columns-work"&gt;Jan 11 - How Keys and Included Columns Work&lt;/h2&gt;
&lt;p&gt;Learn how disk-based rowstore indexes are structured in SQL Server. Why can you seek on key columns? Where are included columns written, and how can you use them? In this demo-based webcast, we&amp;rsquo;ll use undocumented commands in SQL Server to explore the secrets in a real disk-based rowstore index.&lt;/p&gt;
&lt;h2 id="jan-25---dirty-secrets-of-nolock"&gt;Jan 25 - Dirty Secrets of NOLOCK&lt;/h2&gt;
&lt;p&gt;What happens when you use NOLOCK hints in your code, or set your isolation level to READ UNCOMMITTED in SQL Server? Learn the dirty secrets and the potential uses of dirty reads in this free 45 minute webinar.&lt;/p&gt;
&lt;h2 id="feb-8---snapshot-isolation-on-ag-secondaries"&gt;Feb 8 - Snapshot Isolation on AG Secondaries&lt;/h2&gt;
&lt;p&gt;What&amp;rsquo;s really going on with isolation levels when you use a readable secondary in an Availability Group? In this free 45 minute session, we&amp;rsquo;ll explore SNAPSHOT isolation on readable secondaries, and explore how queries on a readable secondary in an AG may impact other replicas.&lt;/p&gt;
&lt;h2 id="feb-22---auto-tuning-with-query-store"&gt;Feb 22 - Auto-Tuning with Query Store&lt;/h2&gt;
&lt;p&gt;Want your database to be self-tuning? Query Store may help! In this demo-based session, we&amp;rsquo;ll explore how auto-tuning in Query Store works: how to configure it, what it does, and how to decide if you like it or not.&lt;/p&gt;
&lt;h2 id="mar-8---why-table-partitioning-doesnt-speed-up-query-performance"&gt;Mar 8 - Why Table Partitioning Doesn&amp;rsquo;t Speed Up Query Performance&lt;/h2&gt;
&lt;p&gt;Learn why SQL Server&amp;rsquo;s table partitioning feature doesn&amp;rsquo;t make your queries faster&amp;ndash; and may even make them slower. Table partitioning can absolutely be worth implementing, but it may be for different reasons than you think! Learn where partitioning shines, and why it&amp;rsquo;s not a simple solution to speed up queries.&lt;/p&gt;
&lt;h2 id="mar-22---max-degree-of-confusion-configuring-maxdop"&gt;Mar 22 - Max Degree of Confusion: Configuring MAXDOP&lt;/h2&gt;
&lt;p&gt;Learn how to configure the max degree of parallelism at the instance, database, and query levels in SQL Server. We&amp;rsquo;ll dig into how many cores a parallel query can use, how this relates to thread count, and guidelines for selecting and testing the right MAXDOP.&lt;/p&gt;
&lt;h2 id="apr-5---fine-tuning-configuring-cost-threshold-for-parallelism"&gt;Apr 5 - Fine Tuning: Configuring Cost Threshold for Parallelism&lt;/h2&gt;
&lt;p&gt;Too many queries going parallel? You get to control the threshold for who qualifies. In this free, 45 minute session, learn what &amp;ldquo;Cost Threshold for Parallelism&amp;rdquo; means, suggested default values, and how to fine tune this setting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Registration has now closed&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Auto-Tuning and the #1 Mindset Problem I Had as a DBA</title><link>https://kendralittle.com/2017/12/04/auto-tuning-and-the-1-mindset-problem-i-had-as-a-dba/</link><pubDate>Mon, 04 Dec 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/12/04/auto-tuning-and-the-1-mindset-problem-i-had-as-a-dba/</guid><description>&lt;p&gt;A few folks have asked: will auto-tuning and adaptive query plans mean the end of performance tuning jobs for SQL Server? In this week&amp;rsquo;s episode, I talk about why I&amp;rsquo;m excited about those features rather than afraid of them.&lt;/p&gt;
&lt;p&gt;Digging into this problem, I share the #1 mindset problem I had as a DBA, why this mindset is so common among database professionals, and a daily habit that can change your approach to new technology.&lt;/p&gt;
&lt;h3 id="audio-version"&gt;Audio version&lt;/h3&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now or read the transcript below? Listen on the go! This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://dearsqldba.libsyn.com/auto-tuning-and-the-1-mindset-problem-i-had-as-a-dba"&gt;Head to the episode page for the audio version&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="video-version"&gt;Video version&lt;/h3&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/o8JwMqBJXQI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript"&gt;Transcript&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: this is a transcript of a chatty webcast, so it&amp;rsquo;s not written like a blog post. It was created by machines and edited by a lady who was also thinking about Hekaton and decoupage at the same time, so it&amp;rsquo;s likely got misspellings, inconsistencies, and grammatical atrocities.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Welcome to Dear SQL DBA, a podcast and YouTube show for SQL Server database administrators and developers. I&amp;rsquo;m Kendra little.&lt;/p&gt;
&lt;h3 id="this-weeks-question"&gt;This week&amp;rsquo;s question&lt;/h3&gt;
&lt;p&gt;This episode I am talking about auto-tuning, as well as the #1 mindset problem that I have had as a database administrator.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve had a few folks ask me the question: you had an episode in the past, Kendra, where you talked about, &amp;ldquo;&lt;a href="https://kendralittle.com/2017/02/23/will-the-cloud-eat-my-dba-job-dear-sql-dba-episode-31/"&gt;will the cloud eat my DBA job&lt;/a&gt;?&amp;rdquo; But, they say, I&amp;rsquo;m still concerned. Now that artificial intelligence is the buzzword for everything, and we&amp;rsquo;ve got all sorts of self tuning features in SQL Server, should I really spend my time investing and building my DBA skills? Especially as a performance tuner? Or is the SQL Server just gonna totally tune itself, so that this is wasted time.&lt;/p&gt;
&lt;h3 id="why-are-people-asking-this-now"&gt;Why are people asking this now?&lt;/h3&gt;
&lt;p&gt;The reason that this question is coming up is because we have things like the first version of an auto tuning feature in query store. which is quite interesting. You may have been hearing things about auto-tuning from the SQL Server marketing materials since SQL Server 2005.&lt;/p&gt;
&lt;p&gt;Those of us have been around for a while have been hearing you won&amp;rsquo;t need to hire a DBA anymore&amp;ndash; we&amp;rsquo;ve been hearing that line for quite a while now, and it&amp;rsquo;s never come true. But the fact that that message is around points out that hiring database administrators or developers who focus on performance tuning is expensive, right? That&amp;rsquo;s a recurring cost, it doesn&amp;rsquo;t come for free.&lt;/p&gt;
&lt;p&gt;And these new features can say&amp;ndash; okay, we&amp;rsquo;ve got query store in SQL Server, where we can configure the database to look at different query plans and gather some aggregate statistics to basically say: okay sometimes this query is fast, and sometimes it&amp;rsquo;s slower. Maybe I can try to pin the faster plan and see if it just gets faster.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a lot of cool stuff in that, right? Like the idea of, maybe some of these tough problems like parameter sniffing that are really tricky to diagnose, when the procedure compiles in one way I get this plan that doesn&amp;rsquo;t work very well, and when it compiles differently I get a better plan. I&amp;rsquo;m just gonna stick with the fast one without even talking to a person. Hey that sounds really really awesome, and that can be great if the faster plan is truly the best plan.&lt;/p&gt;
&lt;h3 id="this-is-a-lot-like-coffee"&gt;This is a lot like coffee&lt;/h3&gt;
&lt;p&gt;You can go to a cafe. I live in Portland Oregon in the United States, and I can go to a cafe and get lovingly handcrafted coffee made by a person with a very advanced degree who has also studied many different kinds of coffee beans, and they&amp;rsquo;re operating a finely crafted machine. And they&amp;rsquo;re just making something beautiful for me.&lt;/p&gt;
&lt;p&gt;And then I can also go to another store where the person presses a button and the coffee&amp;rsquo;s automatically made, and maybe I get the coffee really quickly. It&amp;rsquo;s automatically made and maybe it&amp;rsquo;s even a pretty darn good coffee.&lt;/p&gt;
&lt;p&gt;Is it still as good as the coffee that is lovingly handcrafted by the highly skilled professional who can make great conversation with me, and is really funny while I&amp;rsquo;m getting the coffee?&lt;/p&gt;
&lt;p&gt;No, it&amp;rsquo;s not as good. In some cases I&amp;rsquo;m gonna just want to take the coffee that&amp;rsquo;s cheaper. When cost is the biggest factor, maybe I don&amp;rsquo;t want to interact with the person at all, I just want a good enough coffee. I think there really is something to that.&lt;/p&gt;
&lt;p&gt;But this is something that isn&amp;rsquo;t new if you think about it&lt;/p&gt;
&lt;h3 id="this-isnt-even-specific-to-auto-tuning"&gt;This isn&amp;rsquo;t even specific to auto-tuning&lt;/h3&gt;
&lt;p&gt;Think about SSDs, think about the amount of memory we can put in a server now. Think about increases in just CPU power over the last five years. There&amp;rsquo;s a lot of things that&amp;ndash; I mean we could have terrible code that&amp;rsquo;s really unoptimized, and there&amp;rsquo;s a lot of ways that with buying an expensive server that maybe we do have to replace eventually&amp;ndash; maybe we have to replace it in five years&amp;ndash; but it&amp;rsquo;s cheaper than hiring a DBA and paying their salary for all those five years, right?&lt;/p&gt;
&lt;p&gt;And maybe we replace it faster than five years. It&amp;rsquo;s life cycle through our whole environment maybe is five years, it may not be in production for five years. Because these changes and improvements in what we can do keep coming faster! But the thing is, we&amp;rsquo;ve had these massive improvements in hardware, that you&amp;rsquo;d think oh maybe we don&amp;rsquo;t need performance tuning anymore.&lt;/p&gt;
&lt;p&gt;But I don&amp;rsquo;t think it&amp;rsquo;s that our code just keeps getting worse and worse. It&amp;rsquo;s that we want to do more and more stuff!&lt;/p&gt;
&lt;h3 id="we-want-to-process-more-and-more-information"&gt;We want to process more and more information&lt;/h3&gt;
&lt;p&gt;So at the same time that our hardware is getting faster, and the SQL Server optimizer has been getting more and more clever too, and we&amp;rsquo;ve been getting all these new features with columnstore, in different ways we can process material, all of this stuff is happening. We still&amp;ndash; there&amp;rsquo;s more and more people who want to process data in different ways! There&amp;rsquo;s more and more data.&lt;/p&gt;
&lt;p&gt;Yeah, cost continues to be a factor.&lt;/p&gt;
&lt;p&gt;But the need to do things, there are so many complex choices to make out there with hardware. With which technologies to use. With what are &amp;ndash; how are we going to deliver the data the fastest? How are we going to lay this out in our environment? How are we going to manage this the most quickly? There&amp;rsquo;s so much architecture work to do, that even with advanced auto-tuning, even as this auto-tuning becomes smarter and smarter: whether or not to turn it on, how to design the environment, and how to manage this all&amp;ndash; there is still a lot of work to do in there! And a lot of it has to do with performance.&lt;/p&gt;
&lt;p&gt;Also, when things go wrong, we need a human being to help make it work. And in critical situations, there&amp;rsquo;s more ways that the SQL Server is becoming more intelligent.&lt;/p&gt;
&lt;h3 id="theres-things-like-adaptive-query-processing"&gt;There&amp;rsquo;s things like adaptive query processing&amp;hellip;&lt;/h3&gt;
&lt;p&gt;SQL Server can now start generating query plans that aren&amp;rsquo;t, &amp;ldquo;I&amp;rsquo;m just gonna do this one thing.&amp;rdquo; The query plan has some flexibility built into it. Hey if this join doesn&amp;rsquo;t look like the right join, maybe I can adapt on the second run. But you know, one of the things about this feature: there&amp;rsquo;s a similar feature to this that you&amp;rsquo;ve been able to by in Oracle in the past. And well I&amp;rsquo;ve noticed that there are still Oracle DBAs, right? They still seem to have jobs. They still seem to be doing well.&lt;/p&gt;
&lt;p&gt;And as I think about adaptive query processing and starting to work with it more and more, I think: well when things do get slow, this is gonna be really interesting to figure out! And then, how does this play in with the other auto tuning features? Troubleshooting this and learning when to deploy this just get more and more exciting.&lt;/p&gt;
&lt;h3 id="i-dont-feel-afraid-of-this"&gt;I don&amp;rsquo;t feel afraid of this&lt;/h3&gt;
&lt;p&gt;Yeah, it is possible that eventually auto-tuning will get to the point that it takes all of the performance tuning jobs, but I think that happens at a point where all of the jobs been taken over by artificial intelligence. It&amp;rsquo;s way down the line. It long far into the future, and hopefully as a society at that point we have figured out more about what to do when you have incredibly intelligent technology.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s not just a problem for the DBAs, that is an interesting futurism problem for everyone.&lt;/p&gt;
&lt;p&gt;For the foreseeable future in our lifetime, I really think if you&amp;rsquo;re interested in performance tuning these auto-tuning features are really exciting, and they make your job more interesting.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re moving into this path as a specialist, and you want to specialize more and more, this is an area where learning how you can use this, how you can recognize it, how you can troubleshoot it, how you can configure it, this is a great opportunity.&lt;/p&gt;
&lt;p&gt;Because we&amp;rsquo;re just starting to get this, and we&amp;rsquo;re at a point that could potentially be really exciting.&lt;/p&gt;
&lt;h3 id="if-you-build-your-expertise-in-this-rather-than-fearing-that-its-gonna-take-your-job-its-a-way-you-could-make-your-job-much-cooler"&gt;If you build your expertise in this, rather than fearing that it&amp;rsquo;s gonna take your job, it&amp;rsquo;s a way you could make your job much cooler&lt;/h3&gt;
&lt;p&gt;Even if your current company isn&amp;rsquo;t using this stuff, you can carve out some time in your week. And you gotta you got to be able to say, I&amp;rsquo;m gonna carve out some time and really use it each week, to have a sandbox and play around with this. Even if your company isn&amp;rsquo;t using SQL Server 2017 now, it&amp;rsquo;s absolutely justifiable just if you&amp;rsquo;re on the career path of DBA to say: I need to understand the new features and the latest release, so that when it could help us, when this is a feature that could make a real difference to us, I can recognize it and help point out things that could make this decision worth doing. So education is definitely a responsibility for yourself.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t don&amp;rsquo;t say, ok, just because we have 2008R2 instances still, I can&amp;rsquo;t learn new stuff.&lt;/p&gt;
&lt;p&gt;You really CAN learn new stuff. You can&amp;rsquo;t do it necessarily on that 2008R2 instance.&lt;/p&gt;
&lt;h3 id="this-is-where-the-mindset-problem-comes-in"&gt;This is where the mindset problem comes in&lt;/h3&gt;
&lt;p&gt;When I was thinking about this question, I was thinking back to when I managed SQL 2000 instances, SQL Server 2005 instances. Back in the day I was lucky to often get to work in positions where I got to work on the latest and greatest technologies, in some case before they became released. Which, let me tell you, it has its own downsides. And cool things, too, but it&amp;rsquo;s a double-edged sword.&lt;/p&gt;
&lt;p&gt;But I also worked with some environments where, you know, we couldn&amp;rsquo;t upgrade them. And I say &amp;ldquo;couldn&amp;rsquo;t&amp;rdquo; for political reasons, and for financial reasons.&lt;/p&gt;
&lt;p&gt;But thinking back to my history as a DBA, I always wanted to learn performance tuning. I always had that desire. But I had a mindset that was super problematic, and and I built this mindset as part of my job. If you have this mindset, too, it is the #1 mindset problem that I would work on altering. As a database administrator we tend to develop this habit of scanning the technical world we live in for problems that may occur.&lt;/p&gt;
&lt;p&gt;Part of why we do this is just change planning: &amp;ldquo;what could go wrong?&amp;rdquo;&amp;quot; is a really important thing to think about. Companies&amp;rsquo; data is often critical to the company&amp;rsquo;s survival. Not just a matter of winning or losing a few dollars, but bad things happening can put the company out of business, when it comes to the data. So we tend to get into this mindset of being a protector, and looking for what is going to go wrong.&lt;/p&gt;
&lt;p&gt;This mindset can be very helpful for planning changes, for saying: okay how can I mitigate that risk? We do need to in our jobs identify risk. But the problem is: this mindset can put you in a place where you don&amp;rsquo;t see opportunities in new features. Where you become just fearful.&lt;/p&gt;
&lt;h3 id="i-became-a-person-who-feared-technical-change"&gt;I became a person who feared technical change&lt;/h3&gt;
&lt;p&gt;Is this gonna break my system??? Is this gonna break my job??&lt;/p&gt;
&lt;p&gt;You become habituated to scanning the world for these things.&lt;/p&gt;
&lt;p&gt;We need to as DBAs, not only we do have to look for risks&amp;ndash; we do have to protect the data&amp;ndash; but we also need to get into a mindset of looking for opportunities and possibilities, even if we can&amp;rsquo;t always act on those opportunities. Even if we aren&amp;rsquo;t going to be able to make these possibilities happen in our workplace.&lt;/p&gt;
&lt;h3 id="i-needed-to-change-my-mindset"&gt;I needed to change my mindset&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s very very helpful for you, for your employer, and it also is honestly more FUN to be the person who thinks about the cool things you can do, and recognizes them. Who doesn&amp;rsquo;t feel down just because you can&amp;rsquo;t do them all, but actually just enjoys saying: hey, you know, what if we did this? what would happen then? Who is just interested. Seizes the opportunities. Plays around with stuff, comes up with clever ideas. These are the habits that are going to lead you into that area where you are specializing in the new features.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re either taking your current company into a technology that you helped them find, or maybe you&amp;rsquo;re finding a different job either at your current company, or at another company, where you&amp;rsquo;re doing that, too. But you&amp;rsquo;re finding those possibilities, and you&amp;rsquo;re moving into them. And this may sound just impossible, because I&amp;rsquo;ve got 99 changes to deploy, and they&amp;rsquo;ve all got problems. and it&amp;rsquo;s Friday at 4:20. Well, the way to change this: you can&amp;rsquo;t just suddenly wake up one day and be like, &amp;ldquo;I&amp;rsquo;m gonna be a person who is creative and thinks of possibilities.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="you-cant-just-rationally-decide-hey-im-gonna-change-my-mindset-and-its-done"&gt;You can&amp;rsquo;t just rationally decide, hey I&amp;rsquo;m gonna change my mindset, and it&amp;rsquo;s done&lt;/h3&gt;
&lt;p&gt;But you can do it, you just have to be craftier about it. There are daily habits that you can change to change your mindset.&lt;/p&gt;
&lt;p&gt;One of the things that I have been doing for a while, I&amp;rsquo;ve doing it for a couple months, but I&amp;rsquo;ve been doing it seriously for about twenty days: I started at the end of the day, just making a list of things that I was grateful for. Things that occurred to me for that day. When I first started I was just doing five or six things. That&amp;rsquo;s the one that I&amp;rsquo;ve been doing for longer. But then more recently, I started getting more serious about it, and I have a little booklet. There&amp;rsquo;s maybe sixteen or seventeen lines per page.&lt;/p&gt;
&lt;p&gt;So I just spend a little bit more time doing it, it takes me about four minutes a day. I write a list of things I&amp;rsquo;m grateful for.&lt;/p&gt;
&lt;p&gt;Now this may sound sort of like&amp;ndash; oh that&amp;rsquo;s kind of cheesy.&lt;/p&gt;
&lt;h3 id="it-is-cheesy-but-it-works"&gt;It IS cheesy but it works&lt;/h3&gt;
&lt;p&gt;Yeah, it&amp;rsquo;s totally cheesy. I didn&amp;rsquo;t even realize why it worked until recently. I was watching &lt;a href="https://www.ted.com/talks/shawn_achor_the_happy_secret_to_better_work"&gt;a video&lt;/a&gt; that I saw I recommended on Twitter by &lt;a href="https://twitter.com/erinstellato"&gt;Erin Stellato&lt;/a&gt;, and at the end of this video they recommend that to make employees happier and more productive, at the beginning of the day, one of the things you do is make a list of things that you&amp;rsquo;re grateful about. They point out that part of what this does for you is it puts you in a mindset of scanning the world for things that are good.&lt;/p&gt;
&lt;p&gt;Think about it: this is what we&amp;rsquo;re talking about! Changing your mindset to look for opportunities is very similar and related to this habit of changing your mindset to scan the world and look for things that you&amp;rsquo;re grateful for. A lot of the things that I&amp;rsquo;m grateful for are things that are opportunities and possibilities. Things that excite me, things that I&amp;rsquo;m curious about, as well as things that other people have done, too.&lt;/p&gt;
&lt;p&gt;So changing your mindset, doing a daily habit to write down something that you&amp;rsquo;re grateful for, for me at least, for me personally has really really helped me to become a person who is more open to possibility.&lt;/p&gt;
&lt;p&gt;More interested in reaching out to it, and less fearful of change.&lt;/p&gt;
&lt;p&gt;As a database administrator, if you are in that mindset, too, which is just super easy to get into because we need to protect the data&amp;ndash; I think that one little habit can really change your life for the better.&lt;/p&gt;
&lt;h3 id="tldr"&gt;TLDR;&lt;/h3&gt;
&lt;p&gt;So I don&amp;rsquo;t think auto-tuning is gonna put performance tuners out of business. I do think we&amp;rsquo;re seeing an increasing trend where if you specialized deep, there&amp;rsquo;s so many tools you can work with, and it&amp;rsquo;s so complex that there is a lot of room still for that specialist&amp;ndash; and there is gonna be in the future.&lt;/p&gt;
&lt;p&gt;Thanks for listening to Dear SQL DBA. I&amp;rsquo;m Kendra Little from LittleKendra.com, and I&amp;rsquo;ll talk to you soon.&lt;/p&gt;</description></item><item><title>In-Memory OLTP and Isolation Levels in SQL Server (Webcast Video with Transcript)</title><link>https://kendralittle.com/2017/12/01/in-memory-oltp-and-isolation-levels-in-sql-server-webcast-video/</link><pubDate>Fri, 01 Dec 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/12/01/in-memory-oltp-and-isolation-levels-in-sql-server-webcast-video/</guid><description>&lt;p&gt;I had a great time this week talking about isolation levels with Hekaton &amp;ndash; aka In-Memory OLTP &amp;ndash; aka Memory Optimized tables. Here&amp;rsquo;s a video of the recorded webcast.&lt;/p&gt;
&lt;p&gt;Thanks to everyone who attended, I sincerely enjoyed your questions and comments &amp;ndash; you make giving these webcasts fun. Links to scripts, blog posts, and a transcript are below the video.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: this webcast ran while I was still experimenting with different ways to capture audio and video for live events
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/8ewzETShRVc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="scripts"&gt;Scripts&lt;/h2&gt;
&lt;p&gt;Grab the scripts &lt;a href="https://gist.github.com/LitKnd/8195b58479f1c65c63913055155c7553"&gt;from this gist&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="links-for-in-memory-oltp"&gt;Links for In-Memory OLTP&lt;/h2&gt;
&lt;p&gt;“&lt;a href="http://bit.ly/2016XTPWhitepaper"&gt;SQL Server In-Memory OLTP Internals for SQL Server 2016&lt;/a&gt;” Whitepaper by Kalen Delaney&lt;/p&gt;
&lt;p&gt;“&lt;a href="http://bit.ly/xtp_validate"&gt;Considerations around validation errors 41305 and 41325 on memory optimized tables with foreign keys&lt;/a&gt;” by Denzil Ribeiro&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/database-engine/whats-new-in-sql-server-2016#InMemory"&gt;&amp;ldquo;What&amp;rsquo;s New&amp;rdquo; books online for In-Memory OLTP&lt;/a&gt; (link on page for 2017 what&amp;rsquo;s new)&lt;/p&gt;
&lt;p&gt;Two blog posts on Memory Optimized Table variables from Michael J Swart - &lt;a href="http://michaeljswart.com/2016/03/microsoft-fixed-my-biggest-sql-server-pet-peeve-two-years-ago/"&gt;why he likes them&lt;/a&gt;, and &lt;a href="http://michaeljswart.com/2017/11/postponing-our-use-of-in-memory-oltp/"&gt;why he needs to postpone using them in his environment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ned Otter blogs about In-Memory OLTP, SQL Server, and more at &lt;a href="http://nedotter.com"&gt;http://nedotter.com&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="transcript"&gt;Transcript&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This is a transcript of a live webcast, so it&amp;rsquo;s chatty and not written as a blog post would be. This transcript was prepared by robots and by one woman chasing a corgi, so please forgive word errors, atrocious spelling, inconsistencies, and grammatical goofs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is time to talk about isolation levels and memory optimized tables in SQL Server. Welcome to the webcast!&lt;/p&gt;
&lt;p&gt;I am recording this, and I will attempt to publish this after the webcast. I&amp;rsquo;ll put a link in the quizletter as well as the follow-up email&amp;ndash; so fingers crossed that it goes well, and that the recording is successful.&lt;/p&gt;
&lt;h3 id="what-is-in-memory-oltp"&gt;What is In-Memory OLTP?&lt;/h3&gt;
&lt;p&gt;First off, I&amp;rsquo;m not going to spend a ton of time on this, but I&amp;rsquo;m talking about isolation levels and In- Memory OLTP. Big picture what is In Memory OLTP in SQL Server? This is an entirely new way that data can be stored, accessed, and manipulated in SQL Server that was written in &amp;mdash; well it was released first in SQL Server 2014.&lt;/p&gt;
&lt;p&gt;The name implies that what&amp;rsquo;s special about it is that the data is in memory. But, you know, we use memory for other forms of data storage. We use memory for columnstore, we use memory for disk based indexes.&lt;/p&gt;
&lt;p&gt;What is special about In Memory OLTP is that not just that the data resides in memory, but that the data is really optimized so that primarily the point of this was that we could do lots of little bitty transactions, lots of little bitty modifications fast without blocks. Without latches. So that blocking isn&amp;rsquo;t slowing down tons of tiny inserts.&lt;/p&gt;
&lt;p&gt;Another really cool thing &amp;ndash; something that I think I take for granted, but that is really cool, is that although this technology was redesigned from the ground up, you don&amp;rsquo;t have to create a database where only In Memory OLTP objects reside. You can modify normal databases in SQL Server and have disk based indexes, columnstore indexes &amp;ndash; which are also disk based but can be on In Memory as well, as well as In Memory OLTP all in the same database. And you can manage it with SQL Server Management Studio. It doesn&amp;rsquo;t take special tools to manage this. It&amp;rsquo;s all integrated with the same SQL Server surface area.&lt;/p&gt;
&lt;h3 id="when-can-in-memory-oltp-be-used"&gt;When can In-Memory OLTP be used?&lt;/h3&gt;
&lt;p&gt;This can be used starting in SQL Server 2014. It&amp;rsquo;s much less limited in SQL Server 2016&amp;ndash; they added a lot more to it&amp;ndash; and an important changes in SQL Server 2016 Service Pack 1, we got the ability to use In Memory OLTP in quote &amp;ldquo;lower editions&amp;rdquo; in SQL Server. The less expensive editions in SQL Server.&lt;/p&gt;
&lt;p&gt;So if you want to start experimenting with this, it becomes easier.&lt;/p&gt;
&lt;p&gt;One of the reasons I was really glad about this&amp;ndash; it&amp;rsquo;s not that I really want to use In Memory OLTP on Web Edition. But with a new feature like this, where everything is completely new and completely different, we&amp;rsquo;re not always that excited to go rush into changing our most critical tables in our most critical applications. When we start integrating this into an environment, we want to find places where it may make sense to use, where we can test out and see: do we get benefits? But they&amp;rsquo;re&amp;ndash; maybe it&amp;rsquo;s a logging usage, where we have a way that if it goes down our primary infrastructure isn&amp;rsquo;t impacted. It&amp;rsquo;s really healthy to start experimenting with new features on less critical parts of our environment, and if we aren&amp;rsquo;t lucky enough to have our whole environment on Enterprise Edition, that was really really limiting before now.&lt;/p&gt;
&lt;p&gt;There are some limits. You have quotas on these &amp;ldquo;cheaper&amp;rdquo;&amp;ndash; and I mean cheaper it shouldn&amp;rsquo;t be in scare quotes, they are literally cheaper, Editions of SQL Server. We do have limits on what we can do with In Memory OLTP on those. We don&amp;rsquo;t get to use resource governor, either.&lt;/p&gt;
&lt;p&gt;Historically I&amp;rsquo;ve not been the world&amp;rsquo;s biggest fan of Resource Governor but for In Memory OLTP as well as for columnstore, for different reasons Resource Governor is really really useful to use for In- Memory OLTP. It can help both monitor and configure how much memory is available to and reserved for In Memory OLTP. Really useful feature that is still Enterprise Edition only, also accessible in Dev Edition.&lt;/p&gt;
&lt;p&gt;So it&amp;rsquo;s still definitely worth it, once you get to critical applications, to have Enterprise Edition. But I&amp;rsquo;m really happy for that &amp;ldquo;dipping your toe in&amp;rdquo; reason, and starting to get used to this.&lt;/p&gt;
&lt;h3 id="what-scenarios-may-work-for-in-memory-oltp"&gt;What scenarios may work for In-Memory OLTP?&lt;/h3&gt;
&lt;p&gt;So, when would we use this? In Memory OLTP is not designed as&amp;ndash; is not &amp;ndash; I mean I&amp;rsquo;m not really thinking about the intentions of how it was designed&amp;ndash; but this is NOT a replacement for all our existing stuff in SQL Server.&lt;/p&gt;
&lt;p&gt;If you want a scenario&amp;ndash; where does give you an improvement in performance&amp;ndash; it&amp;rsquo;s not gonna give you an improvement in performance all the time, right? Sometimes, with any change, we can make things slower. The scenarios that currently are the best know possible fit for In Memory OLTP are&amp;ndash; if I have a ton of a little-bitty transactions and I want to insert rapidly, and that&amp;rsquo;s why I mentioned the logging scenario might be a non-critical dip-your-toe-in scenario.&lt;/p&gt;
&lt;p&gt;Something like caching. Now caching I am like, well, that&amp;rsquo;s an expensive cache! We&amp;rsquo;re paying a lot for Enterprise Edition, and we have limits on how much we can cache in lower editions. But depending on your environment, sometimes these things make sense. Fast ingestion of lots of little bits of data.&lt;/p&gt;
&lt;p&gt;We have memory optimized table variables, which if you have a really high access of temporary objects, then memory optimized table variables can take that out of tempdb. It&amp;rsquo;s cool because Michael J Swart has blogged about this: he had high contention in tempdb, and one way he could resolve that was by using memory optimized table variables. Now Michael wrote a recent blog post that&amp;rsquo;s really interesting about why it didn&amp;rsquo;t end up making sense yet in their environment, because they do need to support lots of little bitty databases, and there is a required footprint for In Memory OLTP on their version of SQL Server. That created an issue for them. So you&amp;rsquo;ve got to be careful and test this out, and sometimes you find that maybe it&amp;rsquo;s not a fit for you yet.&lt;/p&gt;
&lt;p&gt;Also we get with In Memory OLTP the ability to have&amp;ndash; this is an option, they are not ALL non-durable&amp;ndash; but you can create with In Memory OLTP an object that if the power gets cut on your SQL Server, the data is all lost. There&amp;rsquo;s some cases where we actually want this! A lot of times we&amp;rsquo;re loading data, and we&amp;rsquo;re manipulating it, and if something goes wrong we&amp;rsquo;re just gonna restart the whole process. We don&amp;rsquo;t care if the data is lost. We don&amp;rsquo;t want the overhead of logging. Non logged, non-durable objects can be great for this. Erin Stellato has written about some testing processes to see if that could be a win for some scenarios, and I would also just leave the door open for different types of things that you can imagine.&lt;/p&gt;
&lt;p&gt;Ned Otter comments: your table variables in In-Memory OLTP will still have the same bad cardinality assumptions. Yeah you can use&amp;ndash; there&amp;rsquo;s a trace flag you can use to help it getan estimate of the number of rows in the table variable, but it&amp;rsquo;s not necessarily going to be faster than a temp table, right? This is true for almost any feature in SQL Server, and when we talk about temp tables vs table variables, this comes up a lot. One is not ALWAYS faster. And that remains true for all of this stuff! You may be able to engineer something really cool with this that you couldn&amp;rsquo;t do with something else, but it isn&amp;rsquo;t just like you swap it in and everything is faster.&lt;/p&gt;
&lt;p&gt;John has a question: does the 32 GB quota affect the buffer pool limit in SQL Server Standard Edition? The quota for In Memory OLTP is a per database quota. My memory &amp;ndash; I&amp;rsquo;m going off my memory here&amp;ndash; is that it is NOT. It is outside that buffer pool limit. The blogpost I have here, the link on the screen, digs into that more. The scenarios post talks about those limits, and Ned please correct me if I&amp;rsquo;m remembering wrong, but I believe it is per database limit and it is not within the buffer pool limit, I believe it is outside of it. I don&amp;rsquo;t have In Memory OLTP in my brain, I have to refresh everything from the cold storage, and I was mainly focusing on the isolation levels for today. Because today&amp;rsquo;s fun is all about isolation levels!&lt;/p&gt;
&lt;h3 id="why-isolation-levels-are-worth-studying-for-in-memory-oltp"&gt;Why Isolation Levels are worth studying for In-Memory OLTP&lt;/h3&gt;
&lt;p&gt;Whatever you&amp;rsquo;re testing, and I really think this is an exciting area of SQL Server to say, &amp;ldquo;hey could I engineer something really fast with this?&amp;rdquo; Whatever you&amp;rsquo;re testing, the isolation levels here can be confusing, because this is really different than disk based rowstore tables in SQL Server and disk based columnstore in SQL Server, as well.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not bad, and I think once you start playing with it it isn&amp;rsquo;t even hard with the In-Memory OLTP isolation levels. In part, because there&amp;rsquo;s only three isolation levels! There&amp;rsquo;s actually fewer isolation levels, and once you get used to how they work, I think it makes sense.&lt;/p&gt;
&lt;p&gt;But it is really different, it&amp;rsquo;s definitely worth playing around with.&lt;/p&gt;
&lt;h3 id="here-are-the-demos-were-going-to-explore-in-this-webcast"&gt;Here are the demos we&amp;rsquo;re going to explore in this webcast&lt;/h3&gt;
&lt;p&gt;Most of what we&amp;rsquo;re doing today is playing around with different demos. You have the demo scripts in your&amp;ndash; oh and Ned just confirmed that my non-In- Memory OLTP brain was correct. The quota is outside of the buffer pool, per DB. If you get into the columnstore index on In Memory OLTP, it does count towards the per DB cap. That&amp;rsquo;s an extra layer of rocket science that you can play around with!&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re gonna dig through these demos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We&amp;rsquo;ll be talking about different kinds of transactions, and why you should care.&lt;/li&gt;
&lt;li&gt;What isolation level escalation is and why you should care. And I this is one of those things that, if you take care of it, you don&amp;rsquo;t necessarily have to worry about it later.&lt;/li&gt;
&lt;li&gt;What is an uncommittable transaction and why is that a good thing?&lt;/li&gt;
&lt;li&gt;Snapshot isolation and multi statement transactions.&lt;/li&gt;
&lt;li&gt;There are three isolation levels. We get snapshot, repeatable read, and serializable. We&amp;rsquo;ll see demos of why you might want repeatable read and serializable.&lt;/li&gt;
&lt;li&gt;Then finally we&amp;rsquo;ll close with a stupid pet trick, and we&amp;rsquo;ll do a recap.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the demos today I am only doing these in interpreted T-SQL. In other words, I am not creating a bunch of natively compiled procedures. I do not mean that natively compiled procedures aren&amp;rsquo;t cool though! In fact, natively compiled procedures, when you can use them, can be incredibly fast. But we can only access in memories tables from natively compiled procedures. There&amp;rsquo;s limitations on what we can do, and I&amp;rsquo;m talking about being creative and exploring. So we are exploring in interpreted T SQL, doing cross container stuff. I have a link if you want to learn more about what this &amp;ldquo;cross container&amp;rdquo; means&amp;ndash; just please know that even though I&amp;rsquo;m not showing you natively compiled procedures, they are really interesting, they are really cool, you should explore them. We just want to play around with isolation levels today.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s dig in now to our SQL Server instance here and bring up our virtual machine. I&amp;rsquo;m doing this on SQL Server 2017 today. Here we are in Management Studio. I am going to need a second Management Studio later, so I will just go ahead and get it open now. Let&amp;rsquo;s make this 100% font and connect up our second instance, and then we will be all sorts are ready to go.&lt;/p&gt;
&lt;p&gt;We are on line 208 in the script. Before this I have done all sorts of setup. I have restored a tiny database called BabbyNames. I have configured it for In Memory OLTP. I have created some tables that we&amp;rsquo;re gonna use, and I have loaded them. I have setup resource governor. You can use the script for download to explore all of that stuff, we just don&amp;rsquo;t have time to show it all today, so I did all that&amp;ndash; I baked that cake before we started.&lt;/p&gt;
&lt;h2 id="autocommit-explicit-and-implicit-transactions"&gt;Autocommit, explicit, and implicit transactions&lt;/h2&gt;
&lt;p&gt;The first weird thing that can be confusing with In Memory OLTP is that what looks like very similar transactions can behave very differently by default. This query: select count star from ref.FirstNameXTP &amp;ndash; I put xtp on the end of my in memory OLTP tables just to make it totally obvious that it&amp;rsquo;s an In Memory table for the purpose of demo, you don&amp;rsquo;t have to do that&amp;ndash; but this is the same query, the only difference is I have it in an explicit transaction in #2.&lt;/p&gt;
&lt;p&gt;And the first example, this is going to be an auto committed transaction &amp;ndash; I haven&amp;rsquo;t explicitly said BEGIN TRAN. But it&amp;rsquo;s gonna run that way. When I run the first statement it works fine, right? No errors. I have ninety five thousand and twenty five rows in the rest of ref.FirstNameXTP table.&lt;/p&gt;
&lt;p&gt;But if I put an explicit transaction around that same query I get an error and the error is actually very clear. Which, you know at least yay for clear errors! It says: accessing memory optimized tables using the read committed isolation level &amp;ndash; my default isolation level in SQL Server is read committed, I don&amp;rsquo;t have read committed snapshot enabled for this database so default, I&amp;rsquo;m using read committed &amp;ndash; it says it&amp;rsquo;s only supported for those auto commit transactions. It is not supported for explicit or implicit transactions.&lt;/p&gt;
&lt;p&gt;I need to provide a supported isolation level using a table hint, and it&amp;rsquo;s even goes so far as to suggest&amp;ndash; it&amp;rsquo;s like a waiter perhaps you would like to use a &amp;ldquo;WITH snapshot&amp;rdquo; hint?&lt;/p&gt;
&lt;p&gt;Well, that&amp;rsquo;s interesting, I need to tell it to use snapshot isolation. And you might wonder from that error message &amp;ndash; it says explicit or implicit transactions. You might be like, okay. what is the difference between auto commit and implicit transactions? I have hardly ever seen people using this in SQL Server, but what it means is you can change this setting and say that implicit transactions are on for my session.&lt;/p&gt;
&lt;p&gt;Then you can run the query, what this essentially does is it secretly puts in a BEGIN TRAN / COMMIT around whatever I run. So it implicitly does that BEGIN TRAN, and I get the same error message as I do for the explicit transaction. I&amp;rsquo;m not saying you should use this, very few people do, I&amp;rsquo;m just showing you so the error message makes sense.&lt;/p&gt;
&lt;p&gt;So, I had to turn my implicit transactions off to return to normal. I can I can turn it off as often as I want :D So what about these auto- commit transactions. Let&amp;rsquo;s look at them a little bit, I do want to just show you and prove the settings for my database because, this this is one of the things that really confused me at first. I can look at sys.databases and see the settings for snapshot isolation, read committed snapshot, and this one we&amp;rsquo;re going to talk about whether or not &amp;ldquo;elevation to snapshot&amp;rdquo; is on.&lt;/p&gt;
&lt;p&gt;Currently in my database that we&amp;rsquo;re using, I have NOT enabled snapshot isolation. This &amp;ldquo;have you enabled snapshot?&amp;rdquo; this is the setting we got in SQL Server 2005 when we got snapshot isolation for disk based tables. They were all we had! That snapshot isolation uses versioning in tempdb, right? I have not turned on tempdb versioning, and I want you to read this as &amp;ldquo;snapshot isolation using tempdb versionin&amp;quot;g when you use this setting, even though that&amp;rsquo;s not what it says. Similarly, I&amp;rsquo;m not doing read committed snapshot, aka &amp;ldquo;RCSI&amp;rdquo;, in tempdb. And I&amp;rsquo;m currently not elevating explicit and implicit transactions to snapshot.&lt;/p&gt;
&lt;p&gt;One of the confusing things to me was: can I tell? What it&amp;rsquo;s telling me is auto commit transactions started in read committed are being elevated to snapshot. Now, part of my confusion was&amp;rdquo; do I have to enable snapshot isolation for this database? That old 2005 version? And then, can I even SEE that they&amp;rsquo;re using snapshot? Well, let&amp;rsquo;s go ahead and&amp;ndash; I&amp;rsquo;m just running this query over and over and over again here. While one equals one, just keep running this query, and while it&amp;rsquo;s running I&amp;rsquo;m going to go into another window and use Adam Machanics&amp;rsquo; sp_whoisactive, which is the great procedure you can get it at WhoIsActive.com for free, it&amp;rsquo;s a great way to see what&amp;rsquo;s running in your SQL Server. And I&amp;rsquo;ve said @get_additional_info = 1, because I want to see information like the transaction isolation level.&lt;/p&gt;
&lt;p&gt;This is completely accurate, this session that I&amp;rsquo;m running, that interpreted TSQL, is in read committed. This statement is sort of secretly getting a WITH SNAPSHOT hint tacked on to it, but that doesn&amp;rsquo;t change the transaction isolation level for the session at all. Even if I do things like @get_plan = 1 to get an execution plan&amp;hellip; and I need plural.. an execution plan isn&amp;rsquo;t super concerned about transaction isolation. This is just about optimization. I don&amp;rsquo;t see any hints tacked on here about &amp;ldquo;WITH SNAPSHOT.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t tell from just looking at the query that this is anything different than plain old vanilla read committed, right? So that&amp;rsquo;s not really&amp;ndash; if you were to just come across this, you wouldn&amp;rsquo;t be like oh that&amp;rsquo;s snapshot isolation, you have to actually play around with this.&lt;/p&gt;
&lt;p&gt;We CAN prove, or at least demonstrate the effects of snapshot isolation. One of the things that you we can do with disk based tables&amp;ndash; and I&amp;rsquo;m going to go ahead and pop this query in here and uncomment it &amp;ndash; with disk based tables if I do this demo, and I go to a disk based index with first names in it&amp;ndash; this table has a lot of names in it and on a disk based index on FirstName, I do have an index on FirstName you&amp;rsquo;re gonna see I forced it to use it. If I take the row Aabin which is the first row that&amp;rsquo;s in here and I update it to zzzAabin, it bounces to the end of that index. And if I&amp;rsquo;m reading it in read committed, if I read it over and over while it&amp;rsquo;s bouncing to the one side of the index and then the other, and then the other, and then the other, on a disk based b-tree index, sometimes I&amp;rsquo;ll count it twice. Sometimes I won&amp;rsquo;t see it all. And that&amp;rsquo;s easy to demo. So what I&amp;rsquo;m going to show show is using supposedly read committed, right? What we know and what we&amp;rsquo;re gonna prove is that with snapshot secretly being added on here, this query we&amp;rsquo;re selecting the name count from, I&amp;rsquo;m forcing it to use an index on the table that I created on FirstName, and if I look at my execution plan I can even see&amp;ndash; yeah I&amp;rsquo;m doing an index scan on FirstName&amp;ndash; what we&amp;rsquo;re gonna do is while we&amp;rsquo;re updating the name and it&amp;rsquo;s NOT bouncing back and forth! That&amp;rsquo;s because this is an In-Memory index.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t the same old b-tree rowstore updates! It doesn&amp;rsquo;t modify our row and move it back and forth.&lt;/p&gt;
&lt;p&gt;In In-Memory OLTP we&amp;rsquo;re just adding new information with timestamps, so SQL Server can figure out what&amp;rsquo;s current. This isn&amp;rsquo;t happening in tempdb, this is a whole new way of the table working, right? So when I&amp;rsquo;m running these updates I&amp;rsquo;m actually ADDING new stuff and with timestamps about what the current information is. So here we go we are &amp;ldquo;updating&amp;rdquo;, which is really just adding new stuff, and then while that happens, I&amp;rsquo;m going to count how many first names there are 2000 times. I want to do this without execution plans on because that&amp;rsquo;ll tank my Management Studio.&lt;/p&gt;
&lt;p&gt;So we have a table that we&amp;rsquo;ve created called NameCount, and we&amp;rsquo;re counting how many rows are in there. If we were really in read committed (against a disk based index) we would see different numbers result from this because sometimes we would miss a name as it was bouncing back and forth in that that disk based b-tree index, and sometimes we would count twice. But now we just have inserts, we don&amp;rsquo;t have updates happening. So let&amp;rsquo;s, actually while it&amp;rsquo;s the working &amp;ndash; it&amp;rsquo;s at about seconds&amp;ndash; I have sp_who_is_active hot keyed, so we can actually watch it as it runs. We can see but see there&amp;rsquo;s no blocking. We are we are still sometimes having to wait on those updates, and memory OLTP does still have to talk to my transaction log, and I am still having some waits on that, but I&amp;rsquo;m not having lock waits going on here, right? What I&amp;rsquo;m running here is sp_whoisactive, I just have it hot keyed. And we finished up there. Alright, so how many names did we count? If we always see 95,025 names&amp;ndash; yeah we are not in plain old read committed. And it&amp;rsquo;s just not using tempdb to do versioning.&lt;/p&gt;
&lt;p&gt;The lowest isolation level that we can have with memory optimized tables is snapshot. That with snapshot hint is getting added on. What about explicit transactions? I&amp;rsquo;m going to review again&amp;ndash; I haven&amp;rsquo;t changed any of my settings, right? I have not enabled elevation. The tempdb version of snapshot isolation is still off. Here&amp;rsquo;s that error I get from the explicit transaction, and it suggests that I add this with snapshot hint. It&amp;rsquo;s like, &amp;ldquo;you might like to have with snapshot&amp;rdquo; Well, okay, let&amp;rsquo;s go ahead and do that. And sure enough that works. The table hint WITH SNAPSHOT works. Now, if you&amp;rsquo;re like me, you might have thought, well another way I could do this is&amp;mdash; if a table hinted with snapshot works, maybe I can just set the isolation level to snapshot on my session? And then I don&amp;rsquo;t have to do all those table hints. Well, in fact, NO. This is part of why it&amp;rsquo;s confusing! Remember, it gives me very clear error &amp;ndash; it says you can&amp;rsquo;t use the session based snapshot on memory optimized tables, and natively compiled modules cannot be accessed or created when you&amp;rsquo;re using session based snapshot.&lt;/p&gt;
&lt;p&gt;The &amp;lsquo;snapshot&amp;rsquo; has to happen as a table hint, not a session hint. And there are reasons for that. I&amp;rsquo;m going to give you a link to Kalen Delaney&amp;rsquo;s whitepaper, and she explains&amp;ndash; there&amp;rsquo;s a very complicated chart, it has to do with if you&amp;rsquo;re accessing disk based stuff and you&amp;rsquo;re accessing In-Memory stuff, you need to have a single timestamp to refer to and because of the different ways they work session level snapshot just doesn&amp;rsquo;t work. So we have to go back to read committed for our session, but it wants the hint not at the session level. If we don&amp;rsquo;t want to type all those hints, here&amp;rsquo;s how we avoid typing all the hints. We say alter database&amp;ndash; I am using alter database current, which we got in SQL Server 2012, but you could put the database name there&amp;ndash; set memory optimized elevate to snapshot on. So now we can see that property in our database, that I do have elevation enabled, and now that I&amp;rsquo;ve set this on my database I can now run this. It ran right without that hint, and it automatically says, &amp;quot; oh that&amp;rsquo;s an In-Memory table, I will add that hint for you.&amp;quot;&lt;/p&gt;
&lt;p&gt;But it is adding that with snapshot hint invisibly in there too make it all work.&lt;/p&gt;
&lt;h3 id="an-uncommittable-transaction-the-seat-stealing-demo"&gt;An uncommittable transaction (the seat-stealing demo)&lt;/h3&gt;
&lt;p&gt;So what about&amp;mdash; what does snapshot isolation give us for this? Well this example is crappy code, but just for illustration purposes, we&amp;rsquo;re gonna talk about getting a seat on an airplane. And I&amp;rsquo;m creating a table named SeatAssignmentsXTP. It has seats, who they&amp;rsquo;re assigned to, and just for fun we&amp;rsquo;re doing some system versioning on the table. You can do versioning on In Memory OLTP tables. The history table is a disk based based table. There&amp;rsquo;s lots of info on that online. I&amp;rsquo;m just doing that for fun, so we can see it. We&amp;rsquo;re gonna put a thousand seats into the table, and then we&amp;rsquo;re gonna update. Let&amp;rsquo;s say all the seats are assigned except for one.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at our seats: there&amp;rsquo;s one seat left, it&amp;rsquo;s in the front of the airplane, and we want to get this seat! The code we have to get the seats is very simple, and this is Just as crappy as the table design. We pass in the seat and the assignee and we are doing an explicit transaction. This is not a memory optimized stored procedure, this is interpreted TSQL in a procedure. It will be automatically escalated. I&amp;rsquo;m doing an update, and then I do a commit. So I want to reserve my seat, and our question is what what happens if we have a race condition, where I&amp;rsquo;m reserving my seat and somebody else comes in and tries to update while I&amp;rsquo;m committing my transaction? To simulate this, what we&amp;rsquo;re gonna do is use the TSQL debugger. I am trying to get my seat. I&amp;rsquo;m gonna say step into, and I&amp;rsquo;m going to step into this procedure. There&amp;rsquo;s the BEGIN TRAN. Now from the update, and while I&amp;rsquo;m on the commit&amp;hellip; at this point where we are trying to commit our data, and while this is happening&amp;mdash; I can close out this window, we don&amp;rsquo;t need it anymore&amp;ndash; while this is happening, someone else tries to reserve a seat in our other Management Studio session.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to connect to the database, there we go, and uncomment the code&amp;ndash; so while I&amp;rsquo;m committing my transaction, Nanners, my old cat, tries to get the seat as well! And she&amp;rsquo;s not debugging, she&amp;rsquo;s just going straight through. So she&amp;rsquo;s gonna go through the update and hit the commit, and when she tries to commit her seat, she gets an error. And this is a feature, I firmly believe this is a feature! Here is the error, here&amp;rsquo;s the number. It&amp;rsquo;s 41302: I tried to update a record that has been updated since this transaction started. I&amp;rsquo;m trying to modify a record that someone else has has modified.&lt;/p&gt;
&lt;p&gt;They&amp;rsquo;re in the process of commit, but I&amp;rsquo;m trying to change data that&amp;rsquo;s been modified since my transaction started. It is not safe to change that data. I had to bail out. This is an uncommitted transaction, it has been rolled back. This is actually a good thing! You want to catch this error, and be like, oh I need to&amp;ndash; actually probably not retry in this case &amp;ndash; maybe retry if the seats available. In theory, the other transaction could roll back too (for some other reason), but this seat is not safe to reserve for Nanners, because kandar is in the process of committing the seat.&lt;/p&gt;
&lt;p&gt;In-Memory OLTP at commit time, it does validation as well as write all the data (to the log). And I am sitting on my commit, it&amp;rsquo;s not safe for anybody&amp;ndash; she can&amp;rsquo;t commit this row, and that&amp;rsquo;s a good thing, right? Because what we don&amp;rsquo;t want to happen is, we don&amp;rsquo;t want to have me commit to the seat and then have her grab the seat from me when it wasn&amp;rsquo;t available for her! So going back to my session, looking at who&amp;rsquo;s assigned to &amp;ndash; our query says that is null right, and I am committing, I am getting that seat! So I finish up, I get my seat, my query is executed successfully. I have one row affected. When we look at the table, yep I have the seat! The seat is assigned to me. We can even use the history, we can use the versioning of this table. I&amp;rsquo;m gonna now say look at the history of this, was there ever a time&amp;ndash; I mean, nanners transaction aborted, but was there ever a time when seat was assigned to anyone else but me? And we can see looking at the history of that seat &amp;ndash; for system time ALL for seat 1a, no this was only ever assigned to me.&lt;/p&gt;
&lt;p&gt;That commit violation is is a useful thing. Don&amp;rsquo;t look at these errors as like, &amp;ldquo;oh it&amp;rsquo;s a problem I have to handle these errors.&amp;rdquo; The errors are there for a reason, and they&amp;rsquo;re trying to be useful for you because I don&amp;rsquo;t want her stealing my seat! Now there&amp;rsquo;s lots of things my code doesn&amp;rsquo;t do, right? This is obviously not modeling code for anything you&amp;rsquo;d actually want to do, but I just like that example for showing with race conditions who gets the seat. What if I&amp;rsquo;m using snapshot and I have more than one statement in the transaction? How does snapshot work? With disk based tables with snapshot isolation, the way I usually do it with disk based tables is, I usually do that transaction isolation level snapshot for my whole session, and then I start a transaction and with that. Then you get a snapshot of the data&amp;ndash; not from the time you run BEGIN TRAN, but from the time you do the first data access.&lt;/p&gt;
&lt;h3 id="multi-statement-transactions-in-snapshot-isolation-the-lemonade-stand-demo"&gt;Multi-statement transactions in Snapshot Isolation (the lemonade stand demo)&lt;/h3&gt;
&lt;p&gt;You get the same view for the whole transaction, which can be useful for reporting&amp;ndash; because let&amp;rsquo;s say I have started a lemonade stand for all of the babbies. This database contains all the baby names in the United States. Let&amp;rsquo;s say a lot of those babies are gonna be running lemonade stands for me. I have this great franchising business, and I need memory optimized tables because there&amp;rsquo;s there&amp;rsquo;s just so many babies selling lemonade. So we&amp;rsquo;re gonna create our lemonade stand revenue XTP table. And we&amp;rsquo;re not going to include the comment ending in the definition. We&amp;rsquo;re actually gonna create the table, now. I have to, on a memory optimized table I always have to have a primary key, it has to be non clustered&amp;ndash; there&amp;rsquo;s no such thing as a clustered index. Oh, brave new world.&lt;/p&gt;
&lt;p&gt;So, I said with memory optimized on, and right now I only have a limited number of revenue. Perhaps we&amp;rsquo;re starting small, but we expect this to be extremely fast in the future! So, I&amp;rsquo;ve got 2015, 2016, 2017, and my total revenue is thirty bucks. We&amp;rsquo;re doing really well here. And we&amp;rsquo;ve got this report on our lemonade stand. The top is a summary query, where we&amp;rsquo;re selecting our total revenue, and then at the bottom we have detail. What we&amp;rsquo;re going to do is, we&amp;rsquo;re going to test out what happens if in the middle of our report the data changes. So first run, we&amp;rsquo;re just going to run our report with no data changing at all. What does our report look like, just by default? As you would expect, our total revenue is thirty, and then here&amp;rsquo;s our detail. Let&amp;rsquo;s say we&amp;rsquo;re running our report&amp;ndash; oops, I keep collapsing it&amp;ndash; there we go&amp;ndash; we start our report and it runs the summary bit, but before it can run the detail bit some data comes in an update. An insert comes in! So in another window &amp;ndash; there we go &amp;ndash; fix our indenting&amp;ndash; in another window, we&amp;rsquo;ve run the first part of our report, which is just automatically escalated to snapshot based on my database setting.&lt;/p&gt;
&lt;p&gt;Meanwhile an insert and an update happen, and for 2017 my revenue is adjusted to $100, and then revenue of $1 comes in for 2014. So our total is no longer $30. We have an extra row, and one of our rows has changed for 2017. When we run now the select detail portion of our report, we don&amp;rsquo;t see the $100. We don&amp;rsquo;t see the row for 2014. This is snapshot isolation working the same way it sees a snapshot from the first time we accessed data in the transaction. We see data consistent with that. Now I commit and it completes successfully. In many situations this is gonna be exactly what we want, because we want consistency with the first time data access occurs in the transaction. But there might be some cases where we don&amp;rsquo;t want this, because what if we want to make sure &amp;ndash; what if we want to make sure that at the time the report commits, at the time of the report is actually given back and returned to the user, it has current data?&lt;/p&gt;
&lt;p&gt;Because in fact the insert and update had committed.&lt;/p&gt;
&lt;h3 id="maybe-we-want-repeatable-read-for-our-report"&gt;Maybe we want Repeatable Read for our report&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s going to be some cases where we want the most recent stuff. We don&amp;rsquo;t want the snapshot from when data access first occurred, we want to say, &amp;ldquo;oh if anything has changed let me know, so I can actually redo it.&amp;rdquo; Because it&amp;rsquo;s not gonna go back and run this first query for me, but I might want it to get to give me an error and let me know, hey something changed!&lt;/p&gt;
&lt;p&gt;Isolation levels can help with this. Our lowest isolation level we can use with In- Memory is snapshot. We can raise one level to repeatable read.&lt;/p&gt;
&lt;p&gt;Repeatable read says, if any of the rows that you have read, if I read them again, and I wouldn&amp;rsquo;t read the exact same thing at the time of commit, I&amp;rsquo;ll throw an error. So I&amp;rsquo;m going to use a read set and look to see if any of those rows would change. Let&amp;rsquo;s reset the table &amp;ndash; oh we can&amp;rsquo;t! Yeah it&amp;rsquo;s different. When you look at this, you&amp;rsquo;re like, oh the truncate table isn&amp;rsquo;t allowed?!?!? But this is a whole new different world, it&amp;rsquo;s not like &amp;ndash; if we delete all the rows or recreate the table, it&amp;rsquo;s not like running through a disk based index in the same way. It stores it differently! There&amp;rsquo;s an interesting discussion as to whether it would be better to delete all rows or recreate the table - I&amp;rsquo;m not covering that today, but test whenever you need to do something like this, and see what&amp;rsquo;s better for you at your volume.&lt;/p&gt;
&lt;p&gt;Now I&amp;rsquo;m going to go ahead and just reinsert my row, so we&amp;rsquo;re back to the original. The original revenue for our massive lemonade stand. Now I have just put a repeatableread hint on the first query. I&amp;rsquo;m gonna start up my report, and I get the summary amount at the top. Now I&amp;rsquo;m just gonna run the update statement, I&amp;rsquo;m not doing the insert. I&amp;rsquo;m just gonna do the update for 2017. A repeatable read hint doesn&amp;rsquo;t catch inserts.&lt;/p&gt;
&lt;p&gt;It doesn&amp;rsquo;t catch what&amp;rsquo;s called phantom rows. This is a change to an existing row that I read. I didn&amp;rsquo;t read this row. I didn&amp;rsquo;t run the insert, but if I had run it it wouldn&amp;rsquo;t have been there at the time I ran my summary query. So I modified a row that this read previously, and now I can run this select query at the end that will return the detailed data, and again it uses the snapshot. I get everything from snapshot but as it hits commit, here it says, &amp;ldquo;Oh, something changed in the readset. You used repeatable read on that first query, and I went and validated what you read, and something&amp;rsquo;s different at the time of commit.&amp;rdquo; So you may want to go check what&amp;rsquo;s going on and rerun that report, because you don&amp;rsquo;t have the most current data. That&amp;rsquo;s a feature, that&amp;rsquo;s the cool feature. If I redo this and I only run the insert statement&amp;ndash; let&amp;rsquo;s reset our table. Repeatable read doesn&amp;rsquo;t catch the insert statement.&lt;/p&gt;
&lt;h3 id="maybe-we-want-serializable-for-our-report"&gt;Maybe we want SERIALIZABLE for our report&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m going to BEGIN TRAN, do this summary with repeatable read, and then I&amp;rsquo;m going to do the insert. Now I haven&amp;rsquo;t changed any of the rows that I read. Now it works just fine on the commit because it says, oh I checked the readset, those are still the same. If I want to catch that insert I need to use serializable isolation level. Serializable includes repeatable read protection, it gives us everything from snapshot, it validates that if we read the rows we read they would be right again. And it says ok, no phantom rows have been inserted that if you were to run the query again you would now read them. So I&amp;rsquo;m gonna reset my table. I&amp;rsquo;m gonna start up my transaction with serializable, and now I&amp;rsquo;m going to just run the update. I&amp;rsquo;m using serializable, not repeatable read.&lt;/p&gt;
&lt;p&gt;While I was doing this a row was updated, and when I go to commit it says it I&amp;rsquo;m using serializable but serializable includes repeatable reads &amp;ndash; so the error message does tell me which type of failure it was. Which type it found first. If I now rerun this and just run the insert&amp;ndash; we&amp;rsquo;re gonna reset the table, and now do the summary transaction. Meanwhile an insert comes in for 2014, which is before the period I read, it&amp;rsquo;s not even in the middle of the period &amp;ndash; now when I go commit, it says, &amp;ldquo;oh your query would have picked up another row&amp;rdquo; and this is a serializable validation feature. So if I do need to make sure that nothing has changed, that if I were to run my select query at the top again that it would return the same stuff, I really want to be in serializable isolation level.&lt;/p&gt;
&lt;h3 id="nolock-and-in-memory-oltp-the-stupid-pet-trick-demo"&gt;NOLOCK and In-Memory OLTP (the stupid pet trick demo)&lt;/h3&gt;
&lt;p&gt;We do have time for a stupid pet trick. I&amp;rsquo;m really pleased! Bonus!&lt;/p&gt;
&lt;p&gt;Oddly enough, the NOLOCK hint is allowed with In-Memory OLTP. No other locking hints are allowed, you can&amp;rsquo;t use XLOCK, it doesn&amp;rsquo;t use locking. You can&amp;rsquo;t tell it rowlock or anything like that. But you can do NOLOCK, which, I wonder if it&amp;rsquo;s a joke? I don&amp;rsquo;t really know. Seems like a joke. What we&amp;rsquo;re gonna do, we&amp;rsquo;re going to start our report right at the beginning of a report I don&amp;rsquo;t want to put any hints on there. We&amp;rsquo;re just returning the summary data. What we&amp;rsquo;re going to do is we&amp;rsquo;re going to now change some of the data here. I&amp;rsquo;m going to update that row, I&amp;rsquo;m gonna insert a row, and then our second statement in the report uses a NOLOCK hint.&lt;/p&gt;
&lt;p&gt;The question is: this seems like what it would do is override the snapshot. You know we&amp;rsquo;re automatically getting elevated, the snapshot this seems like it might &amp;ndash; I don&amp;rsquo;t know why I have two semicolons there, just for emphasis maybe???&lt;/p&gt;
&lt;p&gt;This seems like it would be like&amp;ndash; oh maybe we could see those rows that were modified, because maybe the NOLOCK cancels out the snapshot. The NOLOCK can&amp;rsquo;t&amp;ndash; let&amp;rsquo;s go ahead and run this, it does not see the updated row for 2017.&lt;/p&gt;
&lt;p&gt;It does not see the row we inserted for 2014. The NOLOCK hint is &amp;ldquo;quietly ignored&amp;rdquo; is the wave Kalen Delaney puts it in her excellent white paper on In Memory OLTP.&lt;/p&gt;
&lt;p&gt;So maybe this is a feature meant to be that&amp;ndash; if you have existing code, you don&amp;rsquo;t have to clean out the NOLOCK hints? I&amp;rsquo;m kinda like, you don&amp;rsquo;t want to port existing code like that. If you&amp;rsquo;re lazy enough to not remove your NOLOCKs, you really shouldn&amp;rsquo;t be using In-Memory. Not the feature for you, if you need to save time to that level. So it is more of a stupid pet trick than anything else, I think.&lt;/p&gt;
&lt;p&gt;But, in fact, the no lock hint is allowed&amp;hellip; trivia for you if you go to any sort of conference that has DBA trivia.&lt;/p&gt;
&lt;h3 id="recap-time"&gt;Recap time!&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s do a quick recap of what we covered in our isolation level adventure.&lt;/p&gt;
&lt;p&gt;There there are three isolation levels allowed with in memory OLTP. The lowest level is snapshot.&lt;/p&gt;
&lt;p&gt;If you use auto commit transactions, when you start playing around with this you may not realize you need to do anything special, because little autocommit transactions are automatically elevated to snapshot. But as soon as you do a BEGIN TRAN, or if you&amp;rsquo;re one of the rare people who use implicit transactions, you may start getting errors that in fact you need to add a WITH SNAPSHOT HINT.&lt;/p&gt;
&lt;p&gt;That is a table hint - snapshot. It&amp;rsquo;s not the session level hint.&lt;/p&gt;
&lt;p&gt;The easiest way to handle this is to alter the database and set elevation on for those explicit transactions (not a lot of people use implicit transactions).&lt;/p&gt;
&lt;p&gt;That table level snapshot hint is good for a lot of scenarios.&lt;/p&gt;
&lt;p&gt;If you want to make sure that at the time of commit no rows have changed, rows that you read, in that case you want to use repeatable read isolation. It gives you that additional protection.&lt;/p&gt;
&lt;p&gt;If further, you want to make sure that not only have no rows that I&amp;rsquo;ve read&amp;ndash; not only have they not changed, but also, no phantom rows popped in: if you were to run your queries again they would have been touched by your query&amp;ndash; you want to make sure those phantoms show up, then you need serializable isolation. This is the most isolated your transaction can be from the impacts of other transactions. If it detects any phantoms you will get these serializable validation errors.&lt;/p&gt;
&lt;h3 id="references"&gt;References&lt;/h3&gt;
&lt;p&gt;(&lt;em&gt;Readers, links to this are maintained at the top of this page. I&amp;rsquo;m not duplicating them just so I don&amp;rsquo;t have to try to keep two copies of a link in sync.&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;I really love Kalen Delaney&amp;rsquo;s whitepaper, here is a short link to that whitepaper. I show just one little bit of potential failure here. I showed you the uncommitable transaction violations. There are other examples of different errors that can happen with the error numbers, things you need to think about, things you need to catch, as well. Just a huge amount of information on how this all works, which is really helpful to know.&lt;/p&gt;
&lt;p&gt;I believe Kalen&amp;rsquo;s book updated book on In Memory OLTP for 2016 is out as well, so you can check that out, also. Start with a whitepaper, it&amp;rsquo;s free, it&amp;rsquo;s shorter. This is something you can actually read and consume, I&amp;rsquo;m not saying it isn&amp;rsquo;t work, but I think it&amp;rsquo;s actually really readable. Kalen writes in a really approachable style, so I highly recommend that white paper. I used it for validating things like that NOLOCK hint. Is it actually just ignored or is something else going on? The white paper confirms, yes, it is quietly ignored. Lots of info. I really love to learn by testing, but you also want to find out, &amp;ldquo;okay is this by design?&amp;rdquo; and you know it&amp;rsquo;s not always obvious from what I&amp;rsquo;m learning from my tests, so it&amp;rsquo;s always great to have these sources. That is an official Microsoft whitepaper.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another interesting post that I thought about demoing that didn&amp;rsquo;t have time to show. Uou can do foreign keys with memory optimized tables - in fact the demo script you have today has some foreign keys in it. This is a really interesting post by Denzil Riberio about validation errors with tables with foreign keys and how proper indexing can help minimize those validation errors by limiting the read set in some cases. Really fun, if you like isolation levels. I really like isolation levels &amp;ndash; a little bit ;) If you&amp;rsquo;re using this it&amp;rsquo;s very important, if you&amp;rsquo;re using the foreign keys!&lt;/p&gt;
&lt;h2 id="wrapping-up-and-chatting"&gt;Wrapping up and chatting&lt;/h2&gt;
&lt;p&gt;I have two more webcasts this year &amp;ndash; oh okay so Ned says, &amp;ldquo;I just wanted to say that some of what&amp;rsquo;s in the white paper was dated, even maximum and and memory data etc.&amp;rdquo; Do you mean because it&amp;rsquo;s been changed in 2017? The white paper is &amp;ndash; I should have mentioned this the white paper is for SQL Server 2016, we have SQL Server 2017 and more improvements and enhancements have been added in 2017. What I should do &amp;ndash; let me make a quick note is in the follow-up email for thi,s I want to add a link for the what&amp;rsquo;s new in 2017 page in books online. becaise that&amp;rsquo;ll help cover the what&amp;rsquo;s changed and what&amp;rsquo;s new. I believe Michael Swart talks about this as well in his recent article about the table variables&amp;ndash; the footprint required for the databases I believe has been reduced in 2017. I think that was an example.&lt;/p&gt;
&lt;p&gt;So yeah, Ned said the white paper was written before RTM. Okay, so some of the 2016 things, such as you put even for 2016 no max amount of memory - it&amp;rsquo;s only limited to OS memory. You&amp;rsquo;d think that the Microsoft folks would just quickly update the white paper because Kalen is super diligent about that stuff, but such is the world of publishing. It&amp;rsquo;s difficult with these things!&lt;/p&gt;
&lt;p&gt;Okay so I will now include the link to what&amp;rsquo;s new in 2017 as well as 2016. It&amp;rsquo;s always fun using a rapidly evolving technology because it really is always a research project. And this isn&amp;rsquo;t just In Memory OLTP, this also has to do with columnstore. With columnstore when i was like doing testing on the rebuild or reorganize webcast, there is a whole page in books online on like okay how do I deal with maintaining columnstore indexes, and it didn&amp;rsquo;t even mention one of the big features in 2017. So, yeah. Even Microsoft&amp;rsquo;s documentation - it&amp;rsquo;s hard for it to keep up with the rate of release. This is a good problem to have because the rate of release is so fast. I don&amp;rsquo;t want to say we should slow down the rate of release and wait on the documentation, but it does mean that you&amp;rsquo;ve now got to look at all the blogs, as well as what are all the whitepapers.&lt;/p&gt;
&lt;p&gt;So it is now 9:51, I&amp;rsquo;m looking to see if folks have questions or comments, but if if you don&amp;rsquo;t you get 9 minutes back potentially before your next meeting! So feel free if you don&amp;rsquo;t have a question or comment to bail out, refresh that coffee, take a walk before your next meeting, or grab these scripts. The link is in the chat window as well as in the answered questions. Grab the scripts and just start playing around with this. If you&amp;rsquo;re like &amp;ndash; oh I don&amp;rsquo;t have an instance to play around with this on, I would really encourage you to just for a scratch sandbox sandbox instance (this actually wasn&amp;rsquo;t what I was demoing on today but one of the things I like to use) is just a real quick docker install. I have the video on SQLWorkbooks.com showing just how fast it is to deploy those, and so if you don&amp;rsquo;t want to have like a permanent 2017 instance around&amp;hellip; and developer edition&amp;rsquo;s free so you could just do a permanent 2017 instance, I&amp;rsquo;m not just dissuading you from that&amp;ndash; but if you also just want like a sandbox, going through the effort to figure out how to set up a quick doctor downloaded latest and install and setup means that anytime you can really quickly do that and then play around with something and then get rid of it and it&amp;rsquo;s gone. I like that! You don&amp;rsquo;t have to do it that way, of course.&lt;/p&gt;
&lt;p&gt;John says don&amp;rsquo;t tell my boss I have nine extra minutes. Yeah, no one say anything. A couple folks saying thanks &amp;ndash; I&amp;rsquo;m so glad that you enjoyed this! Thanks for coming!&lt;/p&gt;
&lt;p&gt;Alice says, will you be presenting at SQLBits in London next year? I will not be at SQLBits next year. I do love London, I do love SQL Bits, it&amp;rsquo;s not that I don&amp;rsquo;t love it, it&amp;rsquo;s just next year didn&amp;rsquo;t work out for me. What I&amp;rsquo;ve decided I want to do actually, I don&amp;rsquo;t think I&amp;rsquo;ve told anyone this but it&amp;rsquo;s not like it&amp;rsquo;s big secret, I finally made the decision that I want to do a day-long session on isolation levels. If you&amp;rsquo;ve been watching the webcasts, I&amp;rsquo;ve been preparing this material on why read committed is not everything we want it to be, what can go wrong with read committed; snapshot isolation and read committed snapshot; now I&amp;rsquo;m starting to build this in memory OLTP piece, and I do touch on columnstore in other modules as well. Then coming up on December 14 I&amp;rsquo;ll be talking about serializable and repeatable read in the context of disk based tables. So adding to that piece&amp;ndash; a lot of people inherit databases, maybe it&amp;rsquo;s their vendor database, maybe it&amp;rsquo;s a legacy database that&amp;rsquo;s using serializable, and they don&amp;rsquo;t even realize it and then they start getting locking problems and, &amp;ldquo;Whoa what&amp;rsquo;s going on with this?&amp;rdquo; I do want to add some more modules like maybe some examples with replication subscribers and different isolation levels.&lt;/p&gt;
&lt;p&gt;Ned says &amp;ldquo;thanks for presenting on my favorite topic.&amp;rdquo; Isolation levels and indexes &amp;ndash; which is my favorite? I don&amp;rsquo;t know, they&amp;rsquo;re maybe both be my favorite. Ned, is In Memory OLTP your favorite topic rather than isolation levels?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not yet MY favorite topic, I find really intriguing. To me it&amp;rsquo;s really interesting, I am super glad that it&amp;rsquo;s now available in standard edition and web edition just for that, because if I was still a production DBA I would totally be like&amp;ndash; now this available in cheaper editions, okay where can I play around with this? But if it explodes, I want it to be no big thing. I want to get ahead, and I may not be able to use it in critical stuff soon, just depending on what things my environment is on, but how can I learn as much as I can about this so I can identify places where this may work, and I can learn how to manage it. I can figure out the nature of this beast. I&amp;rsquo;m really glad that they did that. Ned says it&amp;rsquo;s a study unto itself, yes. Everything is different. I was lucky enough to get to go to Kalen Delaney&amp;rsquo;s pre con day on in memory OLTP. It was called &amp;ldquo;what the Hekaton?!?&amp;rdquo;&amp;quot; and I got to attend that in Portugal, and it was like entering&amp;ndash; I mean that&amp;rsquo;s kind of the cool thing about it is spending time on In memory OTP is like entering a totally different world of SQL Server. But in our familiar SQL Server databases, and you get to just totally&amp;ndash; it&amp;rsquo;s like everything&amp;rsquo;s a different color, you know what I mean? You get to explore it and you find everything&amp;rsquo;s different. You have to learn to relax a lot of your assumptions (like clustered indexes exist) and then you&amp;rsquo;re like, well how does it work? It&amp;rsquo;s crazy so it&amp;rsquo;s really fun. It&amp;rsquo;s really interesting.&lt;/p&gt;
&lt;p&gt;Simon says whole thing is a great topic, it&amp;rsquo;s great to chat up girls see how they respond. So I don&amp;rsquo;t know if you saw the Rimma Nehme meme that she used. Doctor Nehme&amp;ndash; hopefully I&amp;rsquo;m saying her name right&amp;ndash; she did a, what do you call it, a morning talk at a conference, a keynote &amp;ndash; at the SQL PASS conference this year and one of the slides she had was a meme about one of the impressive things at parties is to talk about how you know how many different isolation levels there are in the cosmos database.&lt;/p&gt;
&lt;p&gt;At the right party, at the right job interview more likely&amp;hellip; the original reason that I started learning about isolation levels in SQL Server was that I had a particularly disastrous job interview. I was interviewing for a job that I really wanted, I thought it was my dream job and I at one point &amp;ndash; it went so badly, I was totally wrong for the position&amp;ndash; at one point I was asked just to name the isolation levels in SQL Server. I was just like, &amp;ldquo;uh&amp;hellip; NOLOCK?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Okay I did a LITTLE better than that, but after that, after that interview which really did humble me on many topics&amp;ndash; and humility is good! I was like, you know maybe I should learn about those, because I really feel like I should be able to answer that question better. And thus, I started learning about isolation levels.&lt;/p&gt;
&lt;p&gt;Simon is working on his isolation level pick up lines. Do not use those in job interviews, that&amp;rsquo;s my biggest piece of advice.&lt;/p&gt;
&lt;p&gt;So alright, I thank you all for joining me, this has been so much fun, and I&amp;rsquo;ll be back on December 7 talking about indexing for Windowing Functions. We will be back in the disk-based b-tree tables (or rather, rowstore tables). This makes rowstore tables&amp;ndash; the terminology is so funny, I&amp;rsquo;m still like oh wait no, &amp;ldquo;I meant ROWSTORE&amp;rdquo; still. I may have kind of slipped up on this. The proper terminology is our old tables are disk based rowstore. Now we have In-Memory OLTP, and then we have columnstore. Columnstore is usually disk based unless we are combining these. So hopefully I got the terminology right :D&lt;/p&gt;
&lt;p&gt;Thank you all for joining, have a great week maybe I&amp;rsquo;ll figure out how to turn off&amp;hellip;.. (yes I figured out how to turn off the webcast)&lt;/p&gt;</description></item><item><title>Where are key columns stored in a nonclustered index in SQL Server?</title><link>https://kendralittle.com/2017/11/29/where-are-key-columns-stored-in-a-nonclustered-index-in-sql-server/</link><pubDate>Wed, 29 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/29/where-are-key-columns-stored-in-a-nonclustered-index-in-sql-server/</guid><description>&lt;p&gt;Last week&amp;rsquo;s Quizletter featured a quiz on keys vs included columns in SQL Server. I got a great question from a reader:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What do you consider a good reference and/or description of indexes for SQL Server? For example where would you have documentation that explains how the answer to #1 is right?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead of finding links, I thought: what a great subject for a blog series! I&amp;rsquo;m going to step through the questions in the quiz and use some undocumented commands to &amp;ldquo;prove&amp;rdquo; each answer, and we&amp;rsquo;ll learn about the physical structure of disk-based rowstore indexes as we go.&lt;/p&gt;
&lt;h2 id="where-are-keys-physically-stored-in-an-index"&gt;Where are keys physically stored in an index?&lt;/h2&gt;
&lt;p&gt;Our quiz is about a simple table named dbo.UserDatabaseTable, which has a clustered index on a column named RowID. You can recreate the table &lt;a href="https://gist.github.com/LitKnd/3076e7873677c5b29b27cfd3a78e86ce"&gt;using the script here to play along&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The table has a nonclustered index:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_UserDatabaseTable_FirstName_RowID_INCLUDES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserDatabaseTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RowID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CharCol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILLFACTOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The structure for the nonclustered index is summarized as the output from querying the index from sys.dm_db_index_physical stats:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sys_dm_db_index_physical_stats_output.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;The question is: which levels of the index contain the RowID column? (Remember: RowID is a key column in the index).&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="what-do-key-columns-do"&gt;What do key columns do?&lt;/h2&gt;
&lt;p&gt;In a disk-based, rowstore index, key columns define how the index is structured.&lt;/p&gt;
&lt;p&gt;This is useful, because you can seek on those columns.&lt;/p&gt;
&lt;p&gt;Our index has two key columns, in this order: FirstName, RowID.&lt;/p&gt;
&lt;p&gt;So our index is sorted primarily by FirstName, then after that, it is sorted by RowID.&lt;/p&gt;
&lt;h2 id="imagine-that-our-table-contains-only-two-first-names-mister-and-stormy"&gt;Imagine that our table contains only two first names, Mister and Stormy&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say that our table has 3 &amp;lsquo;Mister&amp;rsquo;s and 5 &amp;lsquo;Stormies&amp;rsquo;, with unique RowIDs. We&amp;rsquo;d expect the key columns to be ordered like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/mister-and-stormy-data.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;This data would all fit easily on a single 8KB page in SQL Server. But for the sake of illustration, imagine that it didn&amp;rsquo;t. What if SQL Server had to put this data on three pages?&lt;/p&gt;
&lt;p&gt;In that case, the key columns of the index would be distributed across multiple pages like this, still sorted first by FirstName, and then by RowID:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/data-across-three-pages.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;A few notes about the diagram:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;This index has two levels. Those levels are level 0 (the &amp;ldquo;leaf&amp;rdquo; of the index), and level 1 (the &amp;ldquo;root page&amp;rdquo;). If a bunch of data were added that added enough pages to the leaf such that there wasn&amp;rsquo;t room on the root page to track them all, another level would be added to the index, and the root page would become level 2.&lt;/li&gt;
&lt;li&gt;The FirstName and RowID columns &lt;em&gt;exist&lt;/em&gt; at Level 1 (the root page), but not all rows are present there. Only enough information is stored so that we can seek to lower pages to find the more detailed information we need.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve completely ignored the included column, CharCol from the index definition in this diagram, because I&amp;rsquo;m just focusing on the keys. It will show up in the more detailed examination below. (Spoiler: it&amp;rsquo;s only at the leaf level of the index.)&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve not included some metadata like the FileId where the page is stored, just for simplicity.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="lets-prove-it-with-the-real-table-and-dbcc-page"&gt;Lets prove it with the real table and DBCC PAGE&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re going to use two undocumented tools in SQL Server to look at sample pages at each level of dbo.UserDatabaseTable.&lt;/p&gt;
&lt;p&gt;First, I&amp;rsquo;m going to get a list of one page per level from the undocumented dynamic management view sys.dm_db_database_page_allocations, with this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocated_page_file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocated_page_page_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_page_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_database_page_allocations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UserDatabaseTable&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;detailed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_allocated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocated_page_file_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page_level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This returns my list of sample pages, all of which are in file #1:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/one-page-number-per-level.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;OK! Now we are going to dig in and look at which columns are &lt;em&gt;really&lt;/em&gt; on those pages using the undocumented (but well known) command &lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2006/06/10/how-to-use-dbcc-page/"&gt;DBCC PAGE&lt;/a&gt;. My first step is to turn on trace flag 3604 for my session to divert the output of DBCC page to my session window (instead of the SQL Server error log):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACEON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="level-5-the-root-page"&gt;Level 5: the root page&lt;/h4&gt;
&lt;p&gt;When you run DBCC PAGE against an index page with the &amp;ldquo;dump style&amp;rdquo; set to 3, you get a nice list of which columns are on the page.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the root page of our nonclustered index looks like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/root-page-columns.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;At this level of the index, we have both key columns of the index. The included column, CharCol, is &lt;em&gt;not&lt;/em&gt; present.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re wondering why a first name is &amp;lsquo;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL&amp;hellip;&amp;rsquo;, that is a real value in the table. Much of the data is auto-generated junk across the different letters of the alphabet, so that it&amp;rsquo;s easy for you to create the data with the script above without having to download and restore anything.&lt;/p&gt;
&lt;p&gt;And for my expert friends out there, my screenshots today don&amp;rsquo;t include the KeyHashValue and Row Size columns returned by DBCC page, just to get a narrow view of the keys and save a little space.&lt;/p&gt;
&lt;h4 id="level-4-to-level-1-intermediate-levels"&gt;Level 4 to level 1: intermediate levels&lt;/h4&gt;
&lt;p&gt;Now we&amp;rsquo;re going to peek at pages at the intermediate levels of the index. Remember, what we&amp;rsquo;re looking at here is the names of the columns in the table, which show whether or not that column is present at that level.&lt;/p&gt;
&lt;p&gt;Sure enough, both FirstName and RowID are present at &lt;em&gt;every&lt;/em&gt; intermediate level in the index.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-level-4-sample-data-dbcc-page.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Index Level 4 - sample page&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-level-3-sample-data-dbcc-page.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Index Level 3 - sample page&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-level-2-sample-data-dbcc-page.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Index Level 2 - sample page&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-level-1-sample-data-dbcc-page.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Index Level 1 - sample page&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="level-0-the-leaf"&gt;Level 0: the leaf&lt;/h4&gt;
&lt;p&gt;Now, let&amp;rsquo;s peek at a page in the leaf of the index:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-level-0-sample-data-dbcc-page.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Just like in the root page and the intermediate pages, the FirstName and RowID columns are present.&lt;/p&gt;
&lt;p&gt;Also in the leaf: CharCol, our included column appears! It was &lt;em&gt;not&lt;/em&gt; in any of the other levels we inspected, because included columns only exist in the leaf of a nonclustered index.&lt;/p&gt;
&lt;h2 id="extra-credit"&gt;Extra credit&lt;/h2&gt;
&lt;p&gt;You might look at this and wonder: our query against sys.dm_db_database_page_allocations selected the minimum page number for each level of the index. We know from checking previous pages at other levels that there is data for &amp;lsquo;Arnold&amp;rsquo; in the index, and &amp;lsquo;Arnold&amp;rsquo; is alphabetically before &amp;lsquo;Ingred&amp;rsquo;&amp;hellip; so why are we seeing data for &amp;lsquo;Ingred&amp;rsquo; on the lowest page number in the leaf?&lt;/p&gt;
&lt;p&gt;The answer is that the script that generates this table fragments the index. The lowest page number in a level is not necessarily the first page &amp;ldquo;logically&amp;rdquo; at that level! Our pages are all out of order.&lt;/p&gt;
&lt;p&gt;Grab the script above and play around with defragmenting the index to see how the page numbers change at each level.&lt;/p&gt;
&lt;h2 id="conclusions-revisiting-the-question"&gt;Conclusions: revisiting the question&lt;/h2&gt;
&lt;p&gt;The quiz question that we set out to prove is this: &lt;strong&gt;which levels of the index contain the RowID column (which is a key column in the index)&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;We proved that all key columns in the index are at all levels of the index.&lt;/p&gt;</description></item><item><title>Slowing Down Your Motor Mouth - Presentation Tips for Fast Talkers</title><link>https://kendralittle.com/2017/11/20/slowing-down-your-motor-mouth-presentation-tips-for-fast-talkers/</link><pubDate>Mon, 20 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/20/slowing-down-your-motor-mouth-presentation-tips-for-fast-talkers/</guid><description>&lt;p&gt;Are you worried that you talk too fast when you give a speech, talk, or presentation?&lt;/p&gt;
&lt;p&gt;In this episode, I give you simple, practical tips that I&amp;rsquo;ve used to successfully improve the way I give presentations. Four years ago, I got frustrated feedback from listeners who had a hard time keeping up with my mouth; now I get congratulations that the pace was great.&lt;/p&gt;
&lt;h3 id="audio-version-18-minutes"&gt;Audio version (18 minutes)&lt;/h3&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;h3 id="video-version-18-minutes"&gt;Video version (18 minutes)&lt;/h3&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/aC4lOJvWd0M?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;Welcome to Dear SQL DBA, a podcast that&amp;rsquo;s *usually* for SQL server developers and database administrators. I&amp;rsquo;m Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;p&gt;Now, I think at the end of last week&amp;rsquo;s podcast, I may have promised a technical topic this week. But I got a great question that isn&amp;rsquo;t technical from a listener, and I just wanted to talk about it this week. It&amp;rsquo;s a great time for me to talk about it!&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m talking about slowing down your motor mouth: presentation tips for fast talkers.&lt;/p&gt;
&lt;h3 id="the-question-that-came-up-from-a-listener-in-conversation-was"&gt;The question that came up from a listener in conversation was&amp;hellip;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;When I&amp;rsquo;m giving a presentation, I&amp;rsquo;ve gotten feedback that I&amp;rsquo;m going too fast. What are tips that can help me successfully slow down without making it too slow, or making it weird for the audience?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="this-is-a-question-that-i-know-a-lot-about-because-i-myself-have-gotten-that-feedback"&gt;This is a question that I know a lot about, because I myself have gotten that feedback!&lt;/h3&gt;
&lt;p&gt;But the cool thing is, I just got my feedback from the SQL PASS Summit that was held in Seattle this year, and on my feedback there was one thing that WASN&amp;rsquo;T there.&lt;/p&gt;
&lt;p&gt;No one at all mentioned that I went too fast. No one said I went too slow, either.&lt;/p&gt;
&lt;p&gt;People actually said they liked the pacing, and for me this was really huge, because three years ago / four years ago, I was getting comments that said I spoke too quickly.&lt;/p&gt;
&lt;h3 id="i-thought-about-not-recording-this-topic-and-just-writing-a-blog-post"&gt;I thought about not recording this topic and just writing a blog post&lt;/h3&gt;
&lt;p&gt;Because obviously, I may speak too fast! Recording a vocal podcast about pacing is a risky business. But I thought about it and I realized: you know, no matter how I do, I have to do WAY BETTER than I would have done four years ago!&lt;/p&gt;
&lt;p&gt;This is about progress, not necessarily perfection. And I definitely have tips that can really help you make progress on slowing down and enjoying it while you present.&lt;/p&gt;
&lt;h3 id="what-does-go-slower-really-mean"&gt;What does &amp;ldquo;go slower&amp;rdquo; really mean?&lt;/h3&gt;
&lt;p&gt;I know from experience that when you get this feedback about speaking too quickly, you understand the concept of it, but it&amp;rsquo;s hard to think about actually executing it. Because if you just try to talk slowly, it gets kind&amp;hellip; of&amp;hellip; weird&amp;hellip; and&amp;hellip; you sort&amp;hellip; of&amp;hellip; get&amp;hellip; this&amp;hellip; monotone&amp;hellip; you know like you&amp;rsquo;re talking&amp;hellip; to&amp;hellip; an&amp;hellip; inanimate&amp;hellip; object.&lt;/p&gt;
&lt;p&gt;Trying to just slow down and, focusing on that slow thing: it&amp;rsquo;s hard to do it in a way that is graceful! And it&amp;rsquo;s kind of missing the point. When we say you&amp;rsquo;re talking too fast, the solution often isn&amp;rsquo;t just about slowing down the space between individual words.&lt;/p&gt;
&lt;h3 id="i-think-it-was-paul-randal-who-really-helped-me-think-about-this"&gt;I think it was Paul Randal who really helped me think about this&lt;/h3&gt;
&lt;p&gt;I think I read a blog post from &lt;a href="https://twitter.com/PaulRandal"&gt;Paul&lt;/a&gt; where he mentioned that when he is doing pacing in his talks, he thinks about people who don&amp;rsquo;t speak the language he&amp;rsquo;s speaking as their primary language. They&amp;rsquo;re fluent, but it&amp;rsquo;s not their primary language.&lt;/p&gt;
&lt;p&gt;That helped me think about it in a different way. Now, I&amp;rsquo;m not great with languages, but I do know that you know when you&amp;rsquo;re in a language that&amp;rsquo;s not your own, it isn&amp;rsquo;t necessarily the speed between the words that&amp;rsquo;s that important. Often pauses at the end of a sentence, or at the end of a concept, give you time to help put the words in order in your head and catch up and get the concept to come together.&lt;/p&gt;
&lt;p&gt;So pacing is about not only the meter of the individual words, but also the breaks and the rests that you give people. It isn&amp;rsquo;t only people who don&amp;rsquo;t share a primary language with you that the pauses help. Even if I&amp;rsquo;m speaking in English, and my listeners&amp;rsquo; primary language is English, if I can give pauses at the right point, that helps them have time to reflect. Have time to assimilate different concepts, figure out how their experiences relate to those concepts. It helps them connect with me.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not just the power of the words, the pauses between the words are really helpful for your listeners.&lt;/p&gt;
&lt;p&gt;There was actually a great person at Speaker Idol&amp;ndash; &lt;a href="https://twitter.com/sqllocks"&gt;Jonathan Stewart&lt;/a&gt;-- who talked about these silences, and and his talk was about allowing white space: both on a screen &amp;ndash; on a dashboard, perhaps a technical dashboard &amp;ndash; but also, he gave audible / verbal examples of allowing white space in your words to help your listeners.&lt;/p&gt;
&lt;h3 id="effectively-integrating-pauses-and-making-change-sticky-notes"&gt;Effectively integrating pauses and making change: sticky notes&lt;/h3&gt;
&lt;p&gt;So when I&amp;rsquo;m speaking, what are practical ways that I can actually remember to do this, to help me execute on this? Because just understanding the concept of, &amp;ldquo;You need to try to allow pauses,&amp;rdquo; is one thing. But how do I integrate it?&lt;/p&gt;
&lt;p&gt;Well, one thing that&amp;rsquo;s really helped me is little notes. Little sticky notes.&lt;/p&gt;
&lt;p&gt;I have multiple tips. bit I wouldn&amp;rsquo;t try all of them at once.&lt;/p&gt;
&lt;p&gt;I would get a sticky note and just focus on ONE of them for your next talk.&lt;/p&gt;
&lt;p&gt;What I do is, I put the sticky note &amp;ndash; I always use a laptop when I present, and the audience can&amp;rsquo;t see the screen of the laptop, right? They see the back of my laptop. So I just put the sticky note at the top of the laptop where I can see it. The sticky note is the reminder of the thing I want to work on. Because I&amp;rsquo;m gonna glance at that laptop screen as I go.&lt;/p&gt;
&lt;h3 id="1-control-your-breathing"&gt;1: Control your breathing&lt;/h3&gt;
&lt;p&gt;The first thing that I started working on with presenting, when I was trying to slow down, was controlling my breath.&lt;/p&gt;
&lt;p&gt;At first when you&amp;rsquo;re speaking, on your very first speech, just remembering to breathe means you&amp;rsquo;ve succeeded! You know, the first time you&amp;rsquo;re speaking, I wouldn&amp;rsquo;t worry about too much of this stuff. When you&amp;rsquo;re on your FIRST talk, you just get through it and then celebrate completion!&lt;/p&gt;
&lt;p&gt;But when you start fine-tuning it, taking deep breaths and breathing deeply and comfortably, and pausing to take a deep breath can really give you that moment between sentences.&lt;/p&gt;
&lt;p&gt;Use that moment to prepare for what you&amp;rsquo;re gonna say next. At first when you&amp;rsquo;re in front of people, it&amp;rsquo;s really hard to think. As you just practice that breathing, you start figuring out &amp;ndash; oh I DO have time to actually consciously think about what I&amp;rsquo;m gonna say, instead of just Auto- Speaking as I move through it.&lt;/p&gt;
&lt;p&gt;So my first sticky note that I ever used, just said &amp;lsquo;BREATHE&amp;rsquo; on it. By breathe, I I really mean take a DEEP breath. A good inhale / exhale.&lt;/p&gt;
&lt;h3 id="2-stop-to-drink-water"&gt;2. Stop to drink water&lt;/h3&gt;
&lt;p&gt;The second thing is: take some time to drink water.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;re really comfortable with breathing, and you want to work on your pacing more, it is perfectly fine to stop your talk and pick up a bottle of water or a cup of water, and take a sip.&lt;/p&gt;
&lt;p&gt;It gives your audience that moment while you&amp;rsquo;re doing it. It gives you a break.&lt;/p&gt;
&lt;p&gt;Water is quite helpful when speaking: especially in half hour or hour long talks, you get kind of dehydrated at the end of it! Drinking water before the talk, and then taking time IN the talk to drink water is often helpful. It naturally gets you used to giving the audience a moment.&lt;/p&gt;
&lt;p&gt;It doesn&amp;rsquo;t always necessarily work on audio podcasts&amp;ndash; not necessarily saying that&amp;ndash; but when you&amp;rsquo;re on a stage, and if you&amp;rsquo;re speaking at a conference or a more casual event, stopping to take a drink of water can really really help. I find it just makes me feel more relaxed, more at home. The water is literally quite refreshing.&lt;/p&gt;
&lt;h3 id="3-bring-a-cup-of-warm-tea-and-use-that-as-well"&gt;3. Bring a cup of warm tea, and use that as well&lt;/h3&gt;
&lt;p&gt;Sometimes I do tea instead. I try not to bring up too many caffeinated beverages, because this will eventually backfire on me regarding talking speed.&lt;/p&gt;
&lt;p&gt;I sometimes like to have&amp;ndash; especially in like an hour-long talk or more&amp;ndash; a water AND a tea, and I&amp;rsquo;ll alternate between them. That actually gives me a sense of comfort, relaxation. I like herbal tea, that kind of soothes my throat.&lt;/p&gt;
&lt;p&gt;If you just go with coffee, and your goal is to have a relaxed, enjoyable pace, you may find that the caffeine pushes you in the wrong direction. If it is something that just makes you feel comfortable, you could switch it off with the water and and not take in too much but I think that absolutely a warm beverage can really help.&lt;/p&gt;
&lt;h3 id="4-pause-survey-the-room-and-make-eye-contact"&gt;4. Pause, survey the room, and make eye contact&lt;/h3&gt;
&lt;p&gt;Another thing that I have started challenging myself to do is to pause and make eye contact with different people in the audience.&lt;/p&gt;
&lt;p&gt;If you have kind of a wide room, or a deep room, looking around, meeting different people&amp;rsquo;s eyes, seeing if there&amp;rsquo;s people I recognize&amp;ndash; and if there is someone I recognize sometimes even waving to them.&lt;/p&gt;
&lt;p&gt;The timing of this is important, though: in a really short talk there might not be good spacing for this. But if you&amp;rsquo;re speaking for half an hour or an hour. often there&amp;rsquo;s a time in your talk when you&amp;rsquo;ve come through the completion of a concept, or a section &amp;ndash; you don&amp;rsquo;t want it to be a time when &amp;mdash; you don&amp;rsquo;t want a big pause when you&amp;rsquo;re doing something like switching between a demo or another screen, for example.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t want a pause that makes it seem like, &amp;ldquo;Uh oh I have nothing to say,&amp;rdquo; right?&lt;/p&gt;
&lt;p&gt;To make this pause feel more natural for the audience, this eye contact thing helps. Looking around and making eye contact seems friendly and open at the end of a concept. It gives the audience an opening where they can not only think about what you&amp;rsquo;ve discussed, but they can raise their hand and ask questions without feeling like they&amp;rsquo;re interrupting you. You want to make this the right length&amp;ndash;it&amp;rsquo;s an art&amp;mdash; you have to practice and get used to it, not too long, not too short.&lt;/p&gt;
&lt;p&gt;This is one of those things that when I when I felt comfortable with the breathing, when I felt comfortable drinking water on stage, maybe a little bit of tea, I started saying: &amp;ldquo;Okay well let&amp;rsquo;s see. I&amp;rsquo;ve got an hour-long talk, I&amp;rsquo;m gonna see if I can fit in three times during the talk&amp;ndash; I have three different subjects that I wrap up, where I look around the room and smile, inviting people if they have questions to ask them. If they don&amp;rsquo;t, I&amp;rsquo;ll keep going after.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="5-integrate-smiles-into-your-pauses"&gt;5. Integrate smiles into your pauses&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s a little hard at first to smile into a silence. But it can really work.&lt;/p&gt;
&lt;p&gt;Smiling when you&amp;rsquo;re speaking is also good, but taking a moment when you are breathing, or just before you drink that water, or when you&amp;rsquo;re making eye contact, to smile at your audience helps them feel that you are comfortable with the moment. You&amp;rsquo;re comfortable with the pausing. And it mentally gives them that that feeling of, &amp;ldquo;I am welcome to ask a question if I want.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I still sometimes put a sticky note on my little monitor &amp;ndash; and maybe it just has a drawing of a smiley face on it.&lt;/p&gt;
&lt;p&gt;I saw this tip years ago in a couple different places online, when I was looking for tips for presenting on video: lots of folks out there say that people like to watch videos of people who are smiling.&lt;/p&gt;
&lt;p&gt;When you see a smiling face it naturally helps you feel happier. It&amp;rsquo;s just a human thing.&lt;/p&gt;
&lt;p&gt;So you as the presenter, if you put a little sticky note with a smiley face&amp;ndash; it can be a crude drawing&amp;ndash; it will help you smile at the camera or at your audience. You don&amp;rsquo;t even have to write the word &amp;ldquo;smiley&amp;rdquo;, any crude smiley face can do.&lt;/p&gt;
&lt;h3 id="6-practice-landing-the-talk-gracefully-even-when-youre-behind-schedule"&gt;6. Practice landing the talk gracefully (even when you&amp;rsquo;re behind schedule)&lt;/h3&gt;
&lt;p&gt;Perhaps one of the hardest things of all when it comes to pacing, though is the end of the talk if you are running behind. I personally like to write down when my finish time is supposed to be on a piece of paper and leave it on the desk. I don&amp;rsquo;t tend to do it as a sticky note, I just tend to throw it on the desk or a table if I have one. Because I don&amp;rsquo;t always remember what time is this thing supposed to end!&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;m going through my presentation, and I&amp;rsquo;m either occasionally catching sight of a clock on the wall, or seeing what time it is on my PowerPoint screen, and I know I&amp;rsquo;m approaching that finish, the natural tendency if you&amp;rsquo;re behind can be to speed up. Talk faster. Keep going! oh-I&amp;rsquo;ve-got-to-get-there-I&amp;rsquo;ve-gotta go!&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s the hardest time to pace. It&amp;rsquo;s a really tricky time!&lt;/p&gt;
&lt;p&gt;If you start speeding up nearing the end of your talk, it makes sure audience feel even more nervous because, they probably know what time it is, too. Maybe they have somewhere to go next. If you speed up at the same time they&amp;rsquo;re already starting to look at their watches, it just increases this feeling of tension for them. It&amp;rsquo;s harder for them to listen to you.&lt;/p&gt;
&lt;p&gt;At the end of your talk, it&amp;rsquo;s more important than ever to think about, &amp;ldquo;I want to land this gently.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;When I picture, okay how how does my talk go? Sometimes at the end you feel like you&amp;rsquo;re at the end of a race. But that&amp;rsquo;s really NOT the feeling you want at the end of the talk. It&amp;rsquo;s like you&amp;rsquo;ve got a seaplane and you just want to make a nice gentle landing on the water.&lt;/p&gt;
&lt;p&gt;Maybe that means you end up skipping some slides. You can practice with a projector: there are some ways that you can skip slides that are more graceful than others.&lt;/p&gt;
&lt;p&gt;You could arrow through them quickly, but that gives that audience the sense that they&amp;rsquo;re missing something. This statement, &amp;ldquo;you&amp;rsquo;re going too fast,&amp;rdquo; is another way of saying, &amp;ldquo;we feel like we&amp;rsquo;re missing something,&amp;rdquo; right? Just speeding through slides can do that.&lt;/p&gt;
&lt;p&gt;So depending on your presentation tool, or whether or not you&amp;rsquo;re using slides or notes, practice!&lt;/p&gt;
&lt;p&gt;If I&amp;rsquo;m nearing the end and I need to skip ahead, with my setup: what is the most graceful way I can do that? If you practice it a few times you&amp;rsquo;ll feel much more comfortable when you&amp;rsquo;re coming into the end, because you know you&amp;rsquo;ve got a plan B. &amp;ldquo;Okay I can hit this button, and then that button, and I&amp;rsquo;m close to the end&amp;ndash; I can land it gracefully for the audience.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;It really is a matter of experience and practice.&lt;/p&gt;
&lt;h3 id="recap-time-heres-your-homework"&gt;Recap time: here&amp;rsquo;s your homework&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;So get the sticky notes! Think first about breathing, controlling your breath.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re doing longer talks, consider working in pauses to drink water, possibly get some tea to help keep your throat warm.&lt;/li&gt;
&lt;li&gt;Think also about if people don&amp;rsquo;t speak your language as their primary language, what will help them get into the talk and understand it?&lt;/li&gt;
&lt;li&gt;For people who it is their primary language, what moments will help them put all those thoughts together in their head?&lt;/li&gt;
&lt;li&gt;Challenge yourself: for however many times is optimal during your length of presentation, to look around the room, make eye contact with different people while you you pause, and also to smile at them as you make eye contact. Not necessarily gluing on to their eyes for too long, keep things moving and being friendly and open, while you do a purposeful pause that invites questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember that silence can make it much more compelling to keep listening to you by giving people a moment. By giving people a little room, we can actually help draw them into the talk and help keep them invested with us as we go on that journey towards our goal at the end&amp;hellip; which is always a gentle, soft comfortable landing, where people feel, &amp;ldquo;Yeah we got we really got into stuff! I liked the time that we took to go over everything.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Those are my tips from a person who&amp;ndash; when I get excited I am still a bit of a motor mouth! But I have made so much progress, and I know that you can too.&lt;/p&gt;
&lt;p&gt;Thanks for joining me for Dear SQL DBA. I&amp;rsquo;m Kendra Little from LittleKendra.com. Happy Thanksgiving to everyone in in the United States who is celebrating, and to everyone else who&amp;rsquo;s celebrating too. I&amp;rsquo;ll talk to you soon!&lt;/p&gt;</description></item><item><title>Attempting to Force a Narrow Plan on an Update with Query Store</title><link>https://kendralittle.com/2017/11/15/attempting-to-force-a-narrow-plan-on-an-update-with-query-store/</link><pubDate>Wed, 15 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/15/attempting-to-force-a-narrow-plan-on-an-update-with-query-store/</guid><description>&lt;p&gt;When you force a plan with Query Store, you may not get what you expect. Here&amp;rsquo;s an example.&lt;/p&gt;
&lt;h2 id="my-update-statement-has-two-plans-recorded-by-query-store"&gt;My update statement has two plans recorded by Query Store&lt;/h2&gt;
&lt;p&gt;I have an update statement for a user database table which is known as &amp;ldquo;Query 15&amp;rdquo; in Query Store. Query 15 has two plans: Plan Id 17, and Plan Id 19.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s Plan Id 17 - we&amp;rsquo;ll call it the &amp;ldquo;wide plan&amp;rdquo;. It has an estimated subtree cost of 401.579. I generate this plan if I compile the procedure dbo.UserDatabaseTableTest with @RowID = 800000. This plan gets &amp;lsquo;FULL&amp;rsquo; optimization.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-id-17-wide-plan-1024x438.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s Plan Id 19 - we&amp;rsquo;ll call it the &amp;ldquo;narrow plan&amp;rdquo;. It has an estimated subtree cost of .272. I generate this plan if I compile the procedure dbo.UserDatabaseTableTest with @RowID = 8000. This is considered a &amp;lsquo;TRIVIAL&amp;rsquo; plan.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-id-19-narrow-plan-1024x434.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="i-want-to-force-the-narrow-trivial-plan"&gt;I want to force the &amp;ldquo;narrow&amp;rdquo;/ trivial plan&lt;/h2&gt;
&lt;p&gt;I decide that I want to force Plan Id 19. I click the Force Plan button, confirm, and immediately get a check mark that Query Store is going to try to force this plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Plan-19-is-forced.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="my-narrow-plan-is-nowhere-to-be-found-anymore"&gt;My narrow plan is nowhere to be found anymore!&lt;/h2&gt;
&lt;p&gt;Now that I&amp;rsquo;ve forced this plan, I can&amp;rsquo;t generate Plan Id 19 anymore. No matter how I compile my procedure, I end up with Plan Id 17. Even if I clear my procedure cache. Even if I restart my SQL Server.&lt;/p&gt;
&lt;p&gt;Not only do I get Plan Id 17 (wide plan), when I look at the actual execution plan, it shows that &amp;ldquo;Use plan = true&amp;rdquo;&amp;hellip; in other words, that it &lt;em&gt;is&lt;/em&gt; being forced.&lt;/p&gt;
&lt;p&gt;This update statement&amp;rsquo;s query plan shows an estimated subtree cost of .1896&amp;hellip; (less than 1):&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/wide-plan-use-plan-true-1024x149.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="how-does-this-look-in-query-stores-top-25-resource-consumers-report"&gt;How does this look in Query Store&amp;rsquo;s Top 25 resource consumers report?&lt;/h2&gt;
&lt;p&gt;Good news: the report accurately shows that I&amp;rsquo;m getting Plan Id 17 consistently, although PlanId 19 is still forced (indicated by the check mark):&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/getting-the-wide-plan-although-narrow-is-forced-1024x435.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;I say this is good news because it clearly shows that I&amp;rsquo;m trying to force something that I&amp;rsquo;m not getting, which is something very useful for me to figure out.&lt;/p&gt;
&lt;h2 id="this-is-not-considered-a-failure"&gt;This is not considered a &amp;ldquo;failure&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;When I check the Query Store DMVs, force_failure_count is 0. The last_force_failure_reason_desc is NONE.&lt;/p&gt;
&lt;p&gt;Query Store didn&amp;rsquo;t fail to apply the narrow plan. Instead, it&amp;rsquo;s just deciding not to give it to me, now that I&amp;rsquo;ve forced that plan.&lt;/p&gt;
&lt;p&gt;Seems kinda like an adolescent, doesn&amp;rsquo;t it?&lt;/p&gt;
&lt;h2 id="could-something-more-be-going-on-here-further-tests"&gt;Could something more be going on here? Further tests&amp;hellip;&lt;/h2&gt;
&lt;p&gt;I decided to do some more testing to make sure the behavior I was seeing wasn&amp;rsquo;t due to something else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dropping the table at the beginning of the procedure didn&amp;rsquo;t matter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My procedure recreated the table being updated at the beginning of each run, using a DROP IF EXISTS / CREATE TABLE pattern. I changed this to a CREATE TABLE (if not exists) / TRUNCATE TABLE pattern.&lt;/p&gt;
&lt;p&gt;The behavior remained the same: once I forced the trivial &amp;ldquo;narrow&amp;rdquo; plan, I always got a wide plan &amp;ndash; no matter what @RowID value I compiled the procedure for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adding an &amp;lsquo;OPTIMIZE FOR&amp;rsquo; hint to the UPDATE statement didn&amp;rsquo;t matter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I was quite surprised by the result of this test, but I probably shouldn&amp;rsquo;t have been!&lt;/p&gt;
&lt;p&gt;I added an OPTIMIZE FOR hint to the end of my update statement, like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/optimize-for-hint.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;As long as the plan is NOT forced in Query Store, this query reliably gets the narrow update plan &amp;ndash; because no matter what @RowID is passed in, the low estimate of 800 is &amp;ldquo;sniffed&amp;rdquo; every time the procedure is compiled.&lt;/p&gt;
&lt;p&gt;However, once I force that narrow plan in Query Store, guess what happens?&lt;/p&gt;
&lt;p&gt;Yep, I get a new &amp;ldquo;wide plan&amp;rdquo; which shows full optimization&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/wide-plan-full-optimization-1024x435.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;For you observant folks out there, I recreated the procedure and I changed this statement by adding the OPTIMIZE FOR hint&amp;hellip; so the object_id for the procedure and the query number / plan id numbers have all changed.&lt;/p&gt;
&lt;h2 id="query-store-isnt-supposed-to-force-exact-plans"&gt;Query Store isn&amp;rsquo;t supposed to force exact plans&lt;/h2&gt;
&lt;p&gt;When you force a plan in Query Store, you aren&amp;rsquo;t guaranteed to get the exact plan that you&amp;rsquo;re forcing. For another example of this &lt;a href="http://sqlblog.com/blogs/andrew_kelly/archive/2016/09/18/query-store-forced-doesn-t-always-mean-forced.aspx"&gt;check out Andrew Kelly&amp;rsquo;s post here&lt;/a&gt;. I haven&amp;rsquo;t found an example of folks from Microsoft documenting this, oddly, but it does seem to be true based on experimentation.&lt;/p&gt;
&lt;p&gt;This experiment does raise the question for me: can you force other TRIVIAL plans with Query Store? Or will a forced plan always have FULL optimization? I am adding that to my research list for the future&amp;hellip; but even if I identify an answer, it will very likely be an answer &amp;ldquo;for now&amp;rdquo; which could change at some point.&lt;/p&gt;
&lt;h2 id="what-to-do-with-this-information"&gt;What to do with this information&lt;/h2&gt;
&lt;p&gt;When it comes to plan forcing, whether it&amp;rsquo;s manually done or &amp;ldquo;automatically tuned&amp;rdquo;&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider plan forcing a temporary fix. Look at changing code or indexes to find a permanently stable fast plan that doesn&amp;rsquo;t require forcing.&lt;/li&gt;
&lt;li&gt;Look at whether the plan being forced is the plan that you&amp;rsquo;re getting after it is forced! It may not be identical, even if it&amp;rsquo;s not failing :D&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Kalen Delaney and Inspiration for Adventure</title><link>https://kendralittle.com/2017/11/14/tsql2sday-96-kalen-delaneys-inspiration-for-adventure/</link><pubDate>Tue, 14 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/14/tsql2sday-96-kalen-delaneys-inspiration-for-adventure/</guid><description>&lt;p&gt;&lt;em&gt;This post is part of TSQL Tuesday, &lt;a href="http://tsqltuesday.com"&gt;a monthly blog party&lt;/a&gt;. You&amp;rsquo;re welcome to join in this party: if you&amp;rsquo;d like email notifications of future topics, &lt;a href="https://kendralittle.com/2017/08/21/how-to-get-email-notifications-for-tsqltuesday/"&gt;here&amp;rsquo;s how to set them up&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This month&amp;rsquo;s topic is &lt;a href="https://sqlonice.com/tsql-tuesday-96-folks-who-have-made-a-difference/"&gt;&amp;ldquo;Folks Who Have Made a Difference&amp;rdquo;, by Ewald Cress&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/fig-15-02-2018_01-04-03.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Ewald Cress has given us a prompt &amp;ldquo;to give a shout-out to people (well-known or otherwise) who have made a meaningful contribution to your life in the world of data.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The people in the community who have taught me things and contributed to my life are too many to list, and impossible to rank. So I thought: who made the biggest impression on me in just the last year?&lt;/p&gt;
&lt;h2 id="you-cant-really-predict-what-people-will-remember"&gt;You can&amp;rsquo;t really predict what people will remember&lt;/h2&gt;
&lt;p&gt;Memory is a funny thing: sometimes you try to remember something and fail. Lots of times, we return to memories that are of an event that may have seemed normal at a time. It&amp;rsquo;s just funny what sticks with you.&lt;/p&gt;
&lt;h2 id="kalen-taught-me-about-in-memory-oltp-and-also-about-a-love-of-adventure"&gt;Kalen taught me about In-Memory OLTP, and also about a love of adventure&lt;/h2&gt;
&lt;p&gt;I was lucky enough to attend SQL Saturday Portugal last year. I taught one pre-conference session, then jumped at the chance to attend &lt;a href="http://sqlblog.com/blogs/kalen_delaney/"&gt;Kalen Delaney&lt;/a&gt;&amp;rsquo;s training day on In-Memory OLTP in SQL Server the next day.&lt;/p&gt;
&lt;p&gt;It was a great day of learning about In-Memory technology, and I&amp;rsquo;m happy to say I remember a lot of it &amp;ndash; but I also remember a conversation that I had with Kalen a day or two later at the conference. She mentioned that she was going to visit with a friend locally. She and her family had met this friend years before, when they were traveling in Mexico, and then sailing (by themselves) from Mexico to Hawaii.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a person who gets seasick looking at a bathtub, and I&amp;rsquo;m not particularly strong on geography either, but that seems like &lt;em&gt;a long trip in a sailboat&lt;/em&gt;. I asked about the trip and hearing about it was just delightful. I won&amp;rsquo;t tell the whole story here so that you can ask Kalen about it sometime :D&lt;/p&gt;
&lt;p&gt;This is one of those memories I didn&amp;rsquo;t realize would stick with me, but hearing Kalen talk about sailing that day comes to mind fairly regularly. It always makes me smile, and it always reminds me that &lt;em&gt;adventure is a really important part of life&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;And this isn&amp;rsquo;t just the adventure of trying new technologies (although isn&amp;rsquo;t it perfect that I also learned about In-Memory OLTP from her?). This is also the adventure of going new places and seeing new things! Plan that road trip with the family. Figure out how to fly someplace that you&amp;rsquo;ve never been next year. Really take time off, then come back to work refreshed and ready and inspired.&lt;/p&gt;
&lt;p&gt;Adventure is important. And the memories last a long time &amp;ndash; even for the people who get to hear about them.&lt;/p&gt;</description></item><item><title>The Case of the Weirdly Long COLUMNSTORE_BUILD_THROTTLE Wait</title><link>https://kendralittle.com/2017/11/09/the-case-of-the-weirdly-long-columnstore_build_throttle-wait/</link><pubDate>Thu, 09 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/09/the-case-of-the-weirdly-long-columnstore_build_throttle-wait/</guid><description>&lt;p&gt;A funny thing happened on the way to my filtered nonclustered columnstore demo recently&amp;hellip;&lt;/p&gt;
&lt;p&gt;It was taking &lt;em&gt;forever&lt;/em&gt; to create my demo index.&lt;/p&gt;
&lt;p&gt;My demo table had a unique clustered index created on two columns: FakeBirthDateStamp (DATETIME2(0)), FirstNameByBirthDateId (BIGINT).&lt;/p&gt;
&lt;p&gt;I used the following code to create my filtered nonclustered columnstore index (nccx):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ncci_FirstNameByBirthDate_filtered&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2015-01-11&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But creating the index was super slow. I&amp;rsquo;d limited my dataset size so that populating the table and creating the clustered rowstore index on the table could all be done in less than 2.5 minutes, but this nonclustered columnstore index was taking way longer. I&amp;rsquo;m running it again as I write this post, and it&amp;rsquo;s up to 12 minutes right now &amp;ndash; still going!&lt;/p&gt;
&lt;h2 id="some-clues-memory-grants-and-wait-stats-oh-my"&gt;Some clues&amp;hellip; memory grants and wait stats, oh my&lt;/h2&gt;
&lt;p&gt;Looking in sys.dm_exec_query_memory_grants, I can see that my filtered mccx index create requested ~450MB of memory grant, and got it! Yay! But it&amp;rsquo;s only using under 2MB of memory grant, and its max used grant is 55MB. It&amp;rsquo;s using all four of the cores on my VM, but CPU use total is at a whopping 2%.&lt;/p&gt;
&lt;p&gt;Running Adam Machanic&amp;rsquo;s free &lt;a href="http://whoisactive.com"&gt;sp_WhoIsActive procedure&lt;/a&gt;, I can see that I am constantly waiting on columnstore_build_throttle:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/COLUMNSTORE_BUILD_THROTTLE-1024x91.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="whats-up-with-columnstore_build_throttle"&gt;What&amp;rsquo;s up with columnstore_build_throttle?&lt;/h2&gt;
&lt;p&gt;Denzil Ribeiro has a great post on &lt;a href="https://blogs.msdn.microsoft.com/sqlcat/2015/07/08/sql-2014-clustered-columnstore-index-rebuild-and-maintenance-considerations/"&gt;how columnstore indexes are built&lt;/a&gt;. He writes that while segments can now be built in parallel, the first segment is built with a single thread to see how much of a memory grant is really needed before things get real.&lt;/p&gt;
&lt;p&gt;While this first segment is being built, other threads wait on it, and the other threads all give off COLUMNSTORE_BUILD_THROTTLE.&lt;/p&gt;
&lt;h2 id="am-i-not-getting-past-the-first-segment"&gt;Am I not getting past the first segment?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m a slow writer, so at this point, my test filtered nccx create is up to 22 minutes.&lt;/p&gt;
&lt;p&gt;Reminder: populating the whole database and creating the rowstore clustered index took less than 2.5 minutes.&lt;/p&gt;
&lt;p&gt;At this point in my original test, I had a small realization and a question: could I have screwed up the filter?&lt;/p&gt;
&lt;h2 id="a-test-remove-the-filter"&gt;A test: remove the filter&lt;/h2&gt;
&lt;p&gt;Guess how long it takes to create the &lt;em&gt;same&lt;/em&gt; nccx, but with no filter definition, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ncci_FirstNameByBirthDate_filtered&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;30 seconds or so.&lt;/p&gt;
&lt;p&gt;Not&amp;hellip; we&amp;rsquo;re up to 24 minutes on my repro of the &amp;ldquo;bad filtered nccx&amp;rdquo; create.&lt;/p&gt;
&lt;p&gt;30 seconds.&lt;/p&gt;
&lt;h2 id="aha-i-messed-up-my-filter"&gt;Aha! I messed up my filter!&lt;/h2&gt;
&lt;p&gt;At this point in my testing, I realized this was a case of user error.&lt;/p&gt;
&lt;p&gt;Can you guess what I did wrong?&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t worry if you don&amp;rsquo;t, it took me longer to figure this out than I&amp;rsquo;d like to admit (and I work with this dataset a lot).&lt;/p&gt;
&lt;h2 id="i-used-the-wrong-datatype"&gt;I used the wrong datatype&lt;/h2&gt;
&lt;p&gt;To review, my original index definition was&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ncci_FirstNameByBirthDate_filtered&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2015-01-11&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the FakeBirthDateStamp column is DATETIME2(0).&lt;/p&gt;
&lt;p&gt;&amp;lsquo;2015-01-11&amp;rsquo; will implicitly convert to a DATETIME2(7). Comparing a larger data type to a smaller one often equals BIG TROUBLE in SQL Server.&lt;/p&gt;
&lt;p&gt;I knew this, I just didn&amp;rsquo;t think about it.&lt;/p&gt;
&lt;p&gt;That first index create might complete someday. I&amp;rsquo;m not sure, the longest I&amp;rsquo;ve let it run is 34 minutes before cancelling it.&lt;/p&gt;
&lt;p&gt;But if I correct my index creation definition to this&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ncci_FirstNameByBirthDate_filtered&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flag2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2015-01-11&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATETIME2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It creates in ~41 seconds.&lt;/p&gt;
&lt;p&gt;So, yes, data types really matter :)&lt;/p&gt;
&lt;h2 id="extra-credit-what-about-rowstore-filtered-indexes"&gt;Extra credit: what about rowstore filtered indexes?&lt;/h2&gt;
&lt;p&gt;I just know one of you clever folks is going to ask this eventually, so I went ahead and tested.&lt;/p&gt;
&lt;p&gt;For a rowstore filtered index with a filter on the DATETIME2(0) column, if I create the index with an explicitly correct datatype, it creates in 15-16 seconds.&lt;/p&gt;
&lt;p&gt;If I create the same rowstore filtered index with a &amp;ldquo;sloppy&amp;rdquo; filter that SQL Server implicitly converts, the index creates in 27-30 seconds.&lt;/p&gt;
&lt;p&gt;Both indexes work as expected for sample test queries.&lt;/p&gt;
&lt;p&gt;So I saw a performance difference for both rowstore and columnstore index creation, but it&amp;rsquo;s &lt;em&gt;much&lt;/em&gt; more dramatic with filtered columnstore indexes.&lt;/p&gt;
&lt;h2 id="extra-extra-credit-what-if-i-have-a-different-clustered-index-on-the-table"&gt;Extra extra credit: what if I have a different clustered index on the table?&lt;/h2&gt;
&lt;p&gt;To recap: in this case where I saw the super-slow filtered nonclustered columnstore index create, I had what I&amp;rsquo;ll call &amp;ldquo;Pattern 1&amp;rdquo;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A unique clustered index with compound key = FakeBirthDateStamp DATETIME2(0), FirstNameByBirthDateId BIGINT&lt;/li&gt;
&lt;li&gt;Nonclustered columnstore index with a predicate who has an implicit conversion on FakeBirthdateStamp to DATETIME2(7)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pattern 1 is recommend in &lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/03/06/real-time-operational-analytics-filtered-nonclustered-columnstore-index-ncci/"&gt;Sunil Agarwal&amp;rsquo;s post here&lt;/a&gt;, so that SQL Server can combine scans on the filtered NCCX with seeks on the clustered index.&lt;/p&gt;
&lt;p&gt;I wondered if I&amp;rsquo;d have the same problem if instead I had what I&amp;rsquo;ll call &amp;ldquo;Pattern 2&amp;rdquo;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A clustered PK on FirstNameByBirthDateId BIGINT&lt;/li&gt;
&lt;li&gt;Nonclustered columnstore index with a predicate who has an implicit conversion on FakeBirthdateStamp to DATETIME2(7)&lt;/li&gt;
&lt;li&gt;A filtered rowstore nonclustered index to help find the rest of the rows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pattern 2 is demonstrated in &lt;a href="http://www.nikoport.com/2015/10/29/columnstore-indexes-part-70-filtered-indexes-in-action/"&gt;Niko Neugebauer&amp;rsquo;s post here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And, in fact, with Pattern 2 I do NOT run into the super-slow index create with the implicit conversion on the filter of the NCCX. It takes ~40 seconds.&lt;/p&gt;
&lt;p&gt;Aren&amp;rsquo;t edge conditions fun?&lt;/p&gt;
&lt;h2 id="in-summary"&gt;In summary&amp;hellip;&lt;/h2&gt;
&lt;p&gt;We should all (especially me) get in the habit of explicitly casting literals to the proper data type in any kind of filtered index.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s why I don&amp;rsquo;t think this is a bug. I messed up in my index definition &amp;ndash; being unclear about a datatype is my bad, not the SQL Server&amp;rsquo;s.&lt;/p&gt;</description></item><item><title>Things I Learned from Speaker Idol 2017 at the SQL PASS Summit</title><link>https://kendralittle.com/2017/11/09/things-i-learned-from-speaker-idol-2017-at-the-sql-pass-summit/</link><pubDate>Thu, 09 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/09/things-i-learned-from-speaker-idol-2017-at-the-sql-pass-summit/</guid><description>&lt;p&gt;I was lucky enough to serve as a judge for the &lt;a href="http://itknowledgeexchange.techtarget.com/sql-server/speaker-idol-2017/"&gt;Speaker Idol competition&lt;/a&gt; at the SQL PASS Summit conference this year. One of the great thing about watching presentations and giving feedback on them is that you learn a &lt;em&gt;lot&lt;/em&gt; about speaking by watching sessions and crafting your feedback.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/red-panda-speaking.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;d like to thank everyone who participated. I enjoyed every single presentation, and I learned a ton.&lt;/p&gt;
&lt;p&gt;I wish I had the time to write about everyone, but to keep this reasonably short, here are some highlights of what I was wowed by from the finalists.&lt;/p&gt;
&lt;h2 id="simon-whitely-excitement-is-infectious"&gt;&lt;a href="https://twitter.com/mrsiwhiteley"&gt;Simon Whitely&lt;/a&gt;: excitement is infectious&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s tricky to be excited at the beginning of a presentation without seeming nervous, but Simon showed us how this is done. He&amp;rsquo;s terrific at pacing - he shows you don&amp;rsquo;t have to talk fast to convey excitement. He uses large, controlled hand gestures while he&amp;rsquo;s excited and introducing his topic.&lt;/p&gt;
&lt;p&gt;This gives a sense of being centered and in control, and brings the audience into the excitement in the best way possible. I&amp;rsquo;m going to try to steal those hand gestures.&lt;/p&gt;
&lt;h2 id="jeremy-fry-the-art-of-the-practiced-off-the-cuff-joke"&gt;&lt;a href="https://twitter.com/sqlbinstein"&gt;Jeremy Fry&lt;/a&gt;: the art of the practiced off-the-cuff joke&lt;/h2&gt;
&lt;p&gt;I can be funny, but it&amp;rsquo;s often by accident. (Read into that what you will.) I&amp;rsquo;m not sure I&amp;rsquo;ll ever get to a place where I plan jokes and they work for me&amp;hellip; I just fall right over the punch line. Or forget it.&lt;/p&gt;
&lt;p&gt;One of the cool things about judging Speaker Idol is that sometimes you see a presentation twice. Sometimes not - contestants who make the final can choose to do the same presentation, or pick a new one. Jeremy did his original presentation, and worked in changes based on feedback. This let me see him make the same joke twice, and &lt;em&gt;it worked just as well the second time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to try to steal this one (not everything works for everyone), but I still giggle thinking about it.&lt;/p&gt;
&lt;h2 id="jonathan-stewart-has-the-best-wordsand-the-best-clothes"&gt;&lt;a href="https://twitter.com/SQLLocks"&gt;Jonathan Stewart&lt;/a&gt; has the best words &lt;em&gt;and&lt;/em&gt; the best clothes&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t mean to be shallow by commenting on clothes, but before this Summit I would have said that wearing a suit to compete in Speaker Idol wasn&amp;rsquo;t a great idea, because the PASS Summit is business casual (and some of us put the emphasis on &lt;em&gt;casual&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;But I hadn&amp;rsquo;t seen Jonathan talk. Jonathan not only can wear a suit really well &amp;ndash; and just make it cool, not stuffy &amp;ndash; he can do the same thing with language and phrases. I found myself writing down phrases he used because they were so evocative (&amp;ldquo;suffocating&amp;rdquo;, &amp;ldquo;the first twitter troll&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to start wearing suits, but I hope Jonathan keeps doing it. I &lt;em&gt;am&lt;/em&gt; going to try to build my vocabulary.&lt;/p&gt;
&lt;h2 id="dennes-torres-makes-great-conversation-all-by-himself"&gt;&lt;a href="https://twitter.com/dennes"&gt;Dennes Torres&lt;/a&gt; makes great conversation, all by himself&lt;/h2&gt;
&lt;p&gt;Dennes chose to do a different presentation for the finale of speaker idol, but he did it in a very cool way. In his first presentation, he taught a technical concept by telling a story about a trip to a bookstore. In his second presentation, he continued the story and taught a different concept. Each presentation stood alone, and could be enjoyed by itself, but there was a very cool thread between the two talks as well. Very fun!&lt;/p&gt;
&lt;p&gt;In both presentations, Dennes relayed conversations between multiple characters in the story. He did this without too much exaggeration or play-acting &amp;ndash; and he made it very natural! I really felt drawn into the interplay between the characters.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve experimented with using characters in presentations before, but I&amp;rsquo;ve never built dialogue between the characters as part of the presentation. Dennes showed me how powerful that can be, and now that&amp;rsquo;s on my list of things to do.&lt;/p&gt;
&lt;h2 id="wed-like-to-learn-fromyou"&gt;We&amp;rsquo;d like to learn from &lt;em&gt;you&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;By &amp;ldquo;we&amp;rdquo;, I mean &amp;ldquo;everyone in the SQL Server Community&amp;rdquo;. We&amp;rsquo;d like to learn from you!&lt;/p&gt;
&lt;p&gt;Now is a great time to start thinking about entering into the Speaker Idol competition for 2018. Start planning out a presentation. Submit it to your &lt;a href="http://www.pass.org/Community/Groups/LocalGroups.aspx"&gt;user group&lt;/a&gt;, or some &lt;a href="http://www.sqlsaturday.com/Events.aspx"&gt;SQL Saturdays&lt;/a&gt; you&amp;rsquo;d like to attend. Dive on in!&lt;/p&gt;
&lt;p&gt;If some of the cool things this year&amp;rsquo;s speakers did appeals to you, then try them out. But, most importantly, be yourself. One of the cool things about speaking is that you will find your own voice, and you&amp;rsquo;ll find what works really well for you. This is different for lots and lots of speakers, and you&amp;rsquo;ll find that you&amp;rsquo;re able to show us something new.&lt;/p&gt;
&lt;p&gt;Keep your eye out for the call for speakers around Summer 2018. I promise to blog and tweet about where you can apply when sign-ups are open.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t wait to see what you&amp;rsquo;ve got.&lt;/p&gt;
&lt;h2 id="read-more-about-speaker-idol"&gt;Read more about Speaker Idol!&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://sqlha.com/2017/11/09/look-back-speaker-idol-2017/"&gt;A Look Back at Speaker Idol 2017 by Allan Hirt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://joeydantoni.com/2017/11/09/speaker-idol-2017-a-judges-tale/"&gt;Speaker Idol 2017 - A Judge&amp;rsquo;s Tale by Joey D&amp;rsquo;Antoni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thomaslarock.com/2017/11/hacking-speaker-idol/"&gt;Hacking Speaker Idol by Tom LaRock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>I Thought I Was An Introvert. Turns Out I Was Anxious as #@*] (Dear SQL DBA Episode 53)</title><link>https://kendralittle.com/2017/11/08/dear-sql-dba-i-thought-i-was-an-introvert-turns-out-i-was-anxious-as/</link><pubDate>Wed, 08 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/08/dear-sql-dba-i-thought-i-was-an-introvert-turns-out-i-was-anxious-as/</guid><description>&lt;p&gt;In this week&amp;rsquo;s episode, I&amp;rsquo;m not answering a reader&amp;rsquo;s question. Instead, I&amp;rsquo;m talking about my personal experience with anxiety.&lt;/p&gt;
&lt;p&gt;This episode touches on on healthcare, religion, and squishy emotions &amp;ndash; and there&amp;rsquo;s at least one curse word. I don&amp;rsquo;t talk tech in this episode. (Don&amp;rsquo;t worry, there&amp;rsquo;s more of that coming in future weeks.)&lt;/p&gt;
&lt;p&gt;Oh, and there&amp;rsquo;s a drawing below, if you want the super-short version.&lt;/p&gt;
&lt;h2 id="audio-version"&gt;Audio version&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now? Listen on the go! This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;iframe src="//html5-player.libsyn.com/embed/episode/id/5922114/height/90/theme/custom/autoplay/no/autonext/no/thumbnail/yes/preload/no/no_addthis/no/direction/backward/render-playlist/no/custom-color/87A93A/" width="100%" height="90"&gt;&lt;/iframe&gt;
&lt;h2 id="video-version"&gt;Video version&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WsG7mEfSoek?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Poster version&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/The-Story-of-an-Anxiety-Monster-1024x576.jpg"&gt;
&lt;/figure&gt;</description></item><item><title>SQL PASS Summit 2017 Day 2 - Keynote Notes and Ideas</title><link>https://kendralittle.com/2017/11/02/sql-pass-summit-2017-day-2-keynote-and-ideas/</link><pubDate>Thu, 02 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/02/sql-pass-summit-2017-day-2-keynote-and-ideas/</guid><description>&lt;p&gt;This morning, &lt;a href="https://twitter.com/@rimmanehme"&gt;Dr Rimma Nehme&lt;/a&gt; tells us the story of the birth of &lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/introduction"&gt;Azure Cosmos DB&lt;/a&gt;, a global, scale-out database system.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/rimma-nehme-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;At the beginning of the talk, I can already tell that I&amp;rsquo;m going to recommend you watch the recording&amp;ndash; &lt;a href="http://www.pass.org/summit/2017/PASStv.aspx?watch=7SRi9vyDtWY"&gt;and here it is&lt;/a&gt;! Summarizing this and paying attention simultaneously is going to be tough.&lt;/p&gt;
&lt;p&gt;So what I&amp;rsquo;m going to write today is the ideas I have and highlights that I notice while listening.&lt;/p&gt;
&lt;h2 id="notes-and-ideas"&gt;Notes and ideas&lt;/h2&gt;
&lt;p&gt;Designing this project was a huge challenge, to say the least.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Partitioning is critical for distribution of data (YEP! Also true elsewhere)&lt;/li&gt;
&lt;li&gt;ACID properties are per partition&lt;/li&gt;
&lt;li&gt;A customer&amp;rsquo;s data can be spread across machines, clusters, and regions (but the customer doesn&amp;rsquo;t have to deal with any of these, they pick regions)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The customer experience is &amp;ldquo;like driving a car. You turn the key and go. You don&amp;rsquo;t have to worry about how the engine is working.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The connection between the application and database is typically logical, you can add and remove regions without impacting the application. You can prioritize regions in case of the possibility of failure. (They really thought about the customer here &amp;ndash;  and it shows in the storytelling.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Customers can come and simulate a regional failure.&lt;/em&gt; YES! &amp;ldquo;Making it fail&amp;rdquo; is something that we should be doing, whether in the cloud or not.&lt;/p&gt;
&lt;p&gt;What if a partition goes down? It will go to a partition in another region? Data is always available due to replication.&lt;/p&gt;
&lt;p&gt;Future: multi-master topology. (WHOOOOO&amp;hellip;..)&lt;/p&gt;
&lt;p&gt;Periodically take full backups stored in blob storage. This is for &amp;ldquo;Oops delete&amp;rdquo; scenarios. Is this the most likely cause of data loss for many companies? Dr Nehme didn&amp;rsquo;t say that, but I think maybe :)&lt;/p&gt;
&lt;p&gt;System is designed to scale storage and throughput as the data size grows, as the throughput grows. Behind the scenes: SSD storage, automatically indexed. (How does it decide what to index I wonder?)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This happens on ingest&lt;/li&gt;
&lt;li&gt;No schema versioning needed&lt;/li&gt;
&lt;li&gt;I NEED TO KNOW MORE&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Elastically scales throughput per region depending on activity.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;currency&amp;rdquo; aka &amp;ldquo;bitcoin of Cosmos DB world&amp;rdquo; is the RU. It is rate based and adjustable. Normalized across DB operations - sophisticated costing system. Used machine learning to calculate various query costs against telemetry data collected from hardware on the data centers. (So if you&amp;rsquo;re frustrated that you don&amp;rsquo;t know what a DTU is, well&amp;hellip;.  this is some measurement like Miles Per Gallon, but exactly measuring it yourself isn&amp;rsquo;t going to be easy.)&lt;/p&gt;
&lt;p&gt;Write optimized, latch free database engine to avoid concurrency concepts.&lt;/p&gt;
&lt;p&gt;Failures are inevitable. What happens if communication is interrupted? CAP theorem. Do you want strong consistency/high latency, or eventual consistency/low latency?&lt;/p&gt;
&lt;p&gt;But there are &lt;em&gt;many&lt;/em&gt; consistency models.&lt;/p&gt;
&lt;p&gt;Cosmos offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strong&lt;/li&gt;
&lt;li&gt;Bounded-stateless&lt;/li&gt;
&lt;li&gt;Session&lt;/li&gt;
&lt;li&gt;Consistent prefix&lt;/li&gt;
&lt;li&gt;Eventual&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dr Nehme recommends paper: &lt;a href="https://www.microsoft.com/en-us/research/publication/replicated-data-consistency-explained-through-baseball/"&gt;Replicated Data Consistency Explained Through Baseball&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fun opportunity for digging in here and finding creative ways to make understanding them accessible! (Speakers rejoice)&lt;/p&gt;
&lt;p&gt;Consistency for a price. The customer decides what makes the most sense.&lt;/p&gt;
&lt;p&gt;They offer SLAs in a new way. They had to change the entire MS SLA page&amp;hellip;. &lt;em&gt;ok, that was probably an incredibly hard thing to get done in a large company&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Modern applications aren&amp;rsquo;t static. Needs to be easy to change things. So the object model is &amp;ldquo;schema free/ schema agnostic.&amp;rdquo;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This is a &amp;ldquo;come as you are&amp;rdquo; approach: store the data as is&lt;/li&gt;
&lt;li&gt;Example: document data model. How do you query? Humanly readable as a JSON document.&lt;/li&gt;
&lt;li&gt;At a global scale, no create index/ drop index, alter index&lt;/li&gt;
&lt;li&gt;Data is indexed as a tree&lt;/li&gt;
&lt;li&gt;Basically a union of all the document trees&lt;/li&gt;
&lt;li&gt;You can consolidate them into one, only keep the unique values that are idiosyncratic&lt;/li&gt;
&lt;li&gt;Inverted index&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Are the paths very large in volume? Relatively no. (WHOA)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.vldb.org/pvldb/vol8/p1668-shukla.pdf"&gt;Paper: Schema-agnoistic indexing with Azure DocumentDB / Cosmos DB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bw tree, optimized for SSD, lock free. Copy on write delta updates. Avoid random writes. Structure storage as log. (More details in the paper.) Delta updates treaded as insert, won&amp;rsquo;t block, won&amp;rsquo;t conflict. (Yeah, I totally don&amp;rsquo;t get this at this point.)&lt;/p&gt;
&lt;p&gt;What about SQL queries? (One door in the house.) It&amp;rsquo;s a declarative language, it&amp;rsquo;s a bit different. Have basic components of sql processing system: compiler, code get, query runtime, index planner, many parts.&lt;/p&gt;
&lt;p&gt;There are many other doors into the house as well.&lt;/p&gt;
&lt;h2 id="ideas-about-presenting"&gt;Ideas about presenting&lt;/h2&gt;
&lt;p&gt;I really like the way this talk included complex technical slides, but brought them into a real storytelling event by using chunky marker drawings to highlight information and draw attention to concepts. This worked for both the &amp;ldquo;feel&amp;rdquo; of the talk as well as for explaining the concepts.&lt;/p&gt;
&lt;p&gt;A lot of the slides had black backgrounds and white text, which worked very well in a large, dark keynote room.&lt;/p&gt;
&lt;p&gt;Strong meme game.&lt;/p&gt;
&lt;p&gt;Near the end, the talk featured a Tolstoy reference and &lt;em&gt;joke&lt;/em&gt;. &amp;ldquo;All happy databases are alike, every unhappy database is unique.&amp;rdquo; That filled my inner humanities nerd with pure, sweet love.&lt;/p&gt;</description></item><item><title>SQL PASS Summit 2017: Day 1 Keynote Thoughts and Memories</title><link>https://kendralittle.com/2017/11/01/sql-pass-summit-2017-day-1-keynote-thoughts-and-memories/</link><pubDate>Wed, 01 Nov 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/11/01/sql-pass-summit-2017-day-1-keynote-thoughts-and-memories/</guid><description>&lt;p&gt;Whee! It&amp;rsquo;s the first day of the main SQL PASS Summit conference and I made it to the keynote &lt;em&gt;early&lt;/em&gt; for the first time ever. The hype says we&amp;rsquo;re going to see some great presenters this morning.&lt;/p&gt;
&lt;h2 id="memories-my-first-summit-that-time-i-was-too-shy-to-say-hi-to-mr-denny"&gt;Memories: my first Summit, that time I was too shy to say &amp;ldquo;Hi&amp;rdquo; to Mr. Denny&lt;/h2&gt;
&lt;p&gt;The very first time I attended this conference, I was so excited to attend sessions and learn. I was also excited to connect with others, but I just wasn&amp;rsquo;t sure how.&lt;/p&gt;
&lt;p&gt;I clearly remember seeing &lt;a href="https://twitter.com/mrdenny"&gt;Denny Cherry&lt;/a&gt; in a session &amp;ndash; he was also attending. I recognized his fantastic hair and big smile from the photo he had at the top of his blog posts. I&amp;rsquo;d found his blog several times when tracking down a solution to a problem. I wanted to introduce myself, but I was just too shy.&lt;/p&gt;
&lt;p&gt;And I didn&amp;rsquo;t say hi.&lt;/p&gt;
&lt;p&gt;Years later, I have gotten better at simply saying, &amp;ldquo;Hello! I read your blog, and I want to say thanks for writing.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Denny isn&amp;rsquo;t here at the blogger table this morning, and he&amp;rsquo;s really missed this year. If he&amp;rsquo;s helped &lt;em&gt;you&lt;/em&gt; out too, &lt;a href="https://www.dcac.co/blog/19202"&gt;please send him some love and let him know you&amp;rsquo;re thinking about him&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-summit-is-old-enough-to-vote"&gt;The Summit is old enough to vote&lt;/h2&gt;
&lt;p&gt;Kicking off the keynote, &lt;a href="https://twitter.com/wadamj"&gt;Adam Jorgensen&lt;/a&gt; mentions that this is the 18th SQL PASS Summit. Whoa, I hadn&amp;rsquo;t realized this. I&amp;rsquo;ve seen the PASS Summit change a lot over the last five years, and this is just a fraction of the lifespan of the conference.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Rohan_Kumar_keynote-300x248.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;General Manager of DB systems engineering &lt;a href="https://twitter.com/rohanksql?lang=en"&gt;Rohan Kumar&lt;/a&gt; is leading off the technical portion of the keynote. Rohan is a great speaker, and he starts us off talking about the challenges of leveraging data, cloud, and AI well.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: Our conversation is no longer just about SQL Server databases anymore at this conference. This has been changing over the last few years, and it finally feels really comfortable here: it's no longer forced at all to talk about cloud, and to not be stuck in the concept of a single SQL Server instance.
&lt;/div&gt;
&lt;p&gt;In his talk, Rohan emphasizes community feedback, and valuing how that shapes the product.&lt;/p&gt;
&lt;p&gt;I do believe this is sincere, and it&amp;rsquo;s real. Microsoft has changed a lot as well over the last few years, opening up to new options. Customers can now run SQL Server on Linux. Managed PostGres exists in the cloud. They are listening, and are changing.&lt;/p&gt;
&lt;h2 id="re-imagining-the-data-estate"&gt;&amp;ldquo;Re-imagining the data estate&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t know why, but I get a real kick out of changing terminology. This morning we&amp;rsquo;re talking about the data estate: &amp;ldquo;hybrid&amp;rdquo; technology. This is an acknowledgement that it&amp;rsquo;s not on-premises data OR public cloud data. Instead, there&amp;rsquo;s an &amp;ldquo;and&amp;rdquo; between those two worlds.&lt;/p&gt;
&lt;h2 id="is-sql-server-2017-really-new"&gt;Is SQL Server 2017 really new?&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll be hearing a lot about 2017 features, but Rohan acknowledges that with Microsoft&amp;rsquo;s cloud-first release cadence, a lot of these features and innovations have been released before the &amp;ldquo;boxed&amp;rdquo; product release. To most of us in the room, we&amp;rsquo;re still in parts of that Data Estate where &amp;ldquo;boxed product&amp;rdquo; releases are a big deal, and we&amp;rsquo;re even still a few years behind.&lt;/p&gt;
&lt;p&gt;So to a lot of us in this room, 2017 is still interesting and is new.&lt;/p&gt;
&lt;p&gt;But I do think that the timing of the conference this year, right after a big release, means we won&amp;rsquo;t be hearing too much about huge new features this week. Instead, I think we&amp;rsquo;ll get highlights of what&amp;rsquo;s already shipped, a few new things, and some indications of areas that will continue to see investment.&lt;/p&gt;
&lt;p&gt;And with that, Rohan brings out two Microsoft rockstars, &lt;a href="https://twitter.com/bobwardms"&gt;Bob Ward&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/conorcunningham/"&gt;Conor Cunningham&lt;/a&gt;, to show us some magic.&lt;/p&gt;
&lt;h2 id="bob-ward-and-conor-cunningham-show-us-some-magic"&gt;Bob Ward and Conor Cunningham show us some magic&lt;/h2&gt;
&lt;p&gt;Ooo, this is interesting. Remember RamDisk? Well, we&amp;rsquo;re seeing a demo of &amp;ldquo;Scalable Persistent Memory&amp;rdquo;, a technology from HP, and comparing performance to SSDs.&lt;/p&gt;
&lt;p&gt;It does turn out that reading from memory is way faster than reading from storage, and the idea that this will be supported from Microsoft &lt;em&gt;is&lt;/em&gt; exciting. Traditionally memory mapped as storage has been officially supported for tempdb, and there&amp;rsquo;s been &lt;a href="https://support.microsoft.com/en-us/help/917047/microsoft-sql-server-i-o-subsystem-requirements-for-the-tempdb-databas"&gt;lots of notes and warnings about using it &lt;em&gt;anywhere&lt;/em&gt; else with SQL Server.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;ll be interesting to see if these are also supported with Availability Groups and other features.&lt;/p&gt;
&lt;h2 id="fixing-plan-regression"&gt;Fixing plan regression&lt;/h2&gt;
&lt;p&gt;We get a demo view now of how Query Store and 2017 features can automatically fix plan regression.&lt;/p&gt;
&lt;p&gt;This is an interesting feature. But we do see that there is &lt;em&gt;still&lt;/em&gt; a &amp;ldquo;blip in the matrix&amp;rdquo;, there&amp;rsquo;s a time period when performance takes a dive, and then is automatically fixed.&lt;/p&gt;
&lt;p&gt;For companies that don&amp;rsquo;t have strict performance requirements, this may be enough. But there&amp;rsquo;s still going to be many companies where the unexplained dip in performance is extremely frustrating. Some folks worry that the job of the DBA or developer is going away, but what I see is that a skilled person who can dig into Query Store and make sure that this performance problem doesn&amp;rsquo;t come back again after the next reboot, or the next change to the code &amp;ndash; that person is still going to be really needed.&lt;/p&gt;
&lt;h2 id="rohan-is-back-talking-new-features"&gt;Rohan is back: Talking new features&lt;/h2&gt;
&lt;p&gt;Highlights here are graph data, machine learning with R &amp;amp; Python, and adaptive query processing.&lt;/p&gt;
&lt;p&gt;I like what I&amp;rsquo;m hearing: Rohan says that what we are seeing in 2017 with changes and growth in the query processor is a &lt;em&gt;first step&lt;/em&gt;. That we will be seeing more of this, and that this will be changing.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m truly excited about this and can&amp;rsquo;t wait to see how this feature evolves, and how optimization in SQL Server evolves.&lt;/p&gt;
&lt;p&gt;In fact, one of the things I was really hoping to hear in this keynote was signs that adaptive query processing remains important and will be getting more investment! So color me thrilled that it got some time and focus.&lt;/p&gt;
&lt;h2 id="lets-talk-containers"&gt;Let&amp;rsquo;s talk containers&lt;/h2&gt;
&lt;p&gt;Bring on the engineers! Now up, we get a demo from &lt;a href="https://twitter.com/TobiasSQL"&gt;Tobias Ternstrom&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/mihaelablendea/"&gt;Mihaela Blendea&lt;/a&gt; about using automation and docker to quickly set up a development environment.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve gotten the question from folks, &amp;ldquo;Why would I want to use SQL Server on Docker?&amp;rdquo; And my favorite personal use case is setting up a super quick test environment. But these two are doing it way better than I ever have.&lt;/p&gt;
&lt;h2 id="new-client-tool-microsoft-sql-operations-studio-project-carbon"&gt;New client tool: Microsoft SQL Operations Studio (Project Carbon)&lt;/h2&gt;
&lt;p&gt;WOOOO! For anyone who&amp;rsquo;s a little tired of SSMS, or who uses Linux or a Mac as their primary machine, there&amp;rsquo;s a new tool in town &amp;ndash; and it doesn&amp;rsquo;t just run on Windows.&lt;/p&gt;
&lt;p&gt;SQL Operations Studio is going public and I&amp;rsquo;m incredibly excited that this new tool is becoming available. I can&amp;rsquo;t wait to start using this tool and exploring what it can do.&lt;/p&gt;
&lt;p&gt;I feel like this demo &lt;em&gt;really&lt;/em&gt; needed a download link! Per this post, it sounds like &lt;a href="https://blogs.technet.microsoft.com/dataplatforminsider/2017/11/01/sql-server-2017-and-azure-data-services-the-ultimate-hybrid-data-platform/"&gt;MS SQL Operations Studio will be available for general download in a few weeks&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="azure-sql-database-managed-instances-like-chocolate-and-peanut-butter"&gt;Azure SQL Database Managed Instances: like chocolate and peanut butter&lt;/h2&gt;
&lt;p&gt;Want help from Microsoft managing an instance in the cloud? Rohan talks about this recent project, and how Microsoft wants to continue to invest in this as a way to help people migrate to the cloud.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s also interesting to hear about this product. This has been released for a bit, and when I first heard about it, I honestly wondered how much Microsoft would like this &amp;ldquo;mixed&amp;rdquo; support model after they got into a bit. It seemed like it could go either way. But we did get some time on this with emphasis on it continuing and growing.&lt;/p&gt;
&lt;p&gt;This is an acknowledgement that companies can&amp;rsquo;t all rewrite their existing applications. People still want their SQL Server agent and crazy linked servers.&lt;/p&gt;
&lt;p&gt;And yes, another sign that DBA and developer jobs aren&amp;rsquo;t going away. The support job may be &lt;em&gt;shared&lt;/em&gt; with Microsoft in this product, but someone on the client side still needs to be able to figure out why the heck the code needs to do what it&amp;rsquo;s doing.&lt;/p&gt;
&lt;h2 id="theres-more-demos-but-i-gotta-scoot"&gt;There&amp;rsquo;s more demos, but I gotta scoot&lt;/h2&gt;
&lt;p&gt;Coolness continues onstage, but I gotta wrap this up, fix my links in this post, and get myself collected and prepped for my upcoming session this morning (WHOOOO!)&lt;/p&gt;
&lt;p&gt;Was this a great keynote? No huge announcements. I&amp;rsquo;m excited that Project Carbon is going public (seriously!), and I love the emphasis on community and the indications that Adaptive Query Processing will get lots more love. My life didn&amp;rsquo;t change, but I like the look of the road ahead, and I am nicely warmed up to dive into the conference. I&amp;rsquo;m a happy camper.&lt;/p&gt;
&lt;p&gt;Even if you aren&amp;rsquo;t at the PASS Summit this week, there&amp;rsquo;s more goodness coming, and you can &lt;a href="http://www.pass.org/summit/2017/Live.aspx"&gt;watch it live on the internet, too&lt;/a&gt;! So join us, whether virtually or in Seattle.&lt;/p&gt;</description></item><item><title>Locked Pages, Working Set, and Private Bytes</title><link>https://kendralittle.com/2017/10/19/locked-pages-working-set-and-private-bytes/</link><pubDate>Thu, 19 Oct 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/10/19/locked-pages-working-set-and-private-bytes/</guid><description>&lt;p&gt;One of the great things about writing presentations is that it spurs you to &amp;ldquo;clean up&amp;rdquo; your definitions. When it comes to writing a slide about something, I ask myself, &amp;ldquo;Do I &lt;em&gt;really&lt;/em&gt; know what that is?&amp;rdquo; I check my assumptions, and clarify how I think about something.&lt;/p&gt;
&lt;p&gt;This week I was working with SQL Server memory settings, and I &amp;ldquo;cleaned up&amp;rdquo; my understanding of the following definitions.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/owl-memory-wut-e1508427833530.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="locked-pages-in-memory-setting"&gt;Locked Pages in Memory (setting)&lt;/h2&gt;
&lt;p&gt;“Locked pages” must be kept in physical memory&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This memory can’t be “paged out”&lt;/li&gt;
&lt;li&gt;In other words, disk space (aka the Windows Page File), can’t be swapped in for this memory&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="working-set-of-a-process"&gt;Working Set of a process&lt;/h2&gt;
&lt;p&gt;For a process in Windows, this shows&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How much is physically resident in memory&lt;/li&gt;
&lt;li&gt;May include some memory shared with other applications&lt;/li&gt;
&lt;li&gt;Does NOT include ‘locked’ pages / large pages&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="private-bytes-for-a-process"&gt;Private Bytes for a process&lt;/h2&gt;
&lt;p&gt;For a process in Windows, this shows&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How much memory is allocated&lt;/li&gt;
&lt;li&gt;This includes page file space allocated and standby list&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-do-i-use-these-metrics"&gt;How do I use these metrics?&lt;/h2&gt;
&lt;p&gt;My favorite way to get comfortable with these metrics is to set yourself up with a test SQL Server environment far, far away from production. Get your SQL Server using memory, &lt;a href="https://docs.microsoft.com/en-us/sysinternals/"&gt;download TestLimit64.exe and Process Explorer from Microsoft Sysinternals&lt;/a&gt;, and get to creating memory pressure and watching your metrics!&lt;/p&gt;
&lt;p&gt;Want to know how things change when you lock pages, or change your Windows page file configuration? These tools will let you see it in action, rather than guessing.&lt;/p&gt;
&lt;h2 id="sources--further-reading"&gt;Sources / further reading&lt;/h2&gt;
&lt;p&gt;This classic blog post by Bob Ward talks about Locked Pages for SQL Server in this &lt;a href="https://blogs.msdn.microsoft.com/psssql/2009/09/11/fun-with-locked-pages-awe-task-manager-and-the-working-set/"&gt;classic post from 2009&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This msdn page defines &lt;a href="https://msdn.microsoft.com/en-us/library/windows/desktop/cc441804.aspx"&gt;what the Working Set for a process is&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This Stack Overflow question and answer &lt;a href="https://stackoverflow.com/questions/1984186/what-is-private-bytes-virtual-bytes-working-set"&gt;compares Private Bytes, Working Set, and Virtual Bytes &amp;ndash; and explains what&amp;rsquo;s tricky about these measurements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to go way deeper, the Windows Internals books and &lt;a href="https://blogs.technet.microsoft.com/markrussinovich/"&gt;Mark Russinovich&amp;rsquo;s blog posts&lt;/a&gt; are for you!&lt;/p&gt;</description></item><item><title>My Two Sessions at the SQL PASS Summit 2017</title><link>https://kendralittle.com/2017/10/12/im-giving-two-sessions-at-the-sql-pass-summit/</link><pubDate>Thu, 12 Oct 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/10/12/im-giving-two-sessions-at-the-sql-pass-summit/</guid><description>&lt;p&gt;&lt;a href="http://www.pass.org/summit/2017/About.aspx"&gt;PASS Summit&lt;/a&gt; sessions have been scheduled, and I&amp;rsquo;m excited to be giving two sessions this year AND helping judge Speaker Idol!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m looking forward to teaching, learning a ton, and connecting with lots of people who love working with data.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Speaking.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="why-did-my-clever-index-change-backfire"&gt;Why Did My Clever Index Change Backfire?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Wednesday, Nov 1, 10:45 AM, Room 6A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Table partitioning is a fantastic tool to help you manage tables with skyrocketing rowcounts. SQL Server 2016 SP1 made table partitioning available in Standard Edition, so you may be planning to add partitioning to your database. But some queries may get slower after you partition your tables: the SQL Server optimizer doesn’t always use indexes the same way after those indexes are partitioned into chunks.&lt;/p&gt;
&lt;p&gt;This session teaches you to use execution plans to troubleshoot regressed queries using partitioned tables. You will learn what “non-aligned” indexes are, how to tell how many partitions a query is really using, and see options for TSQL and indexing changes to speed up your queries.&lt;/p&gt;
&lt;h2 id="when-partitioning-hurts-performance-and-how-to-fix-it"&gt;When Partitioning Hurts Performance (and How to Fix It)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Friday, Nov 3, 8 am, 6B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SQL Server is full of advanced techniques to build powerful indexes: indexed views, filtered indexes, columnstore indexes, and more. Many of these techniques have risks, however: your cool indexing idea may just backfire and leave your users frustrated.&lt;/p&gt;
&lt;p&gt;In this session, you&amp;rsquo;ll see multiple demos of how different indexing patterns may slow down queries, have dangerous side effects, or not work at all. You&amp;rsquo;ll learn what to test, how to identify index problems in query execution plans, and how to sidestep these indexing blunders. If you have a solid knowledge of index basics are are comfortable reading query execution plans, this session will improve your index tuning skills.&lt;/p&gt;
&lt;h2 id="speaker-idol"&gt;Speaker Idol&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Round 1: Wednesday, Nov 1, 4:45 PM, Skagit 4 (TCC Lower Level)&lt;/li&gt;
&lt;li&gt;Round 2: Thursday, Nov 2, 3:15 PM , Skagit 4 (TCC Lower Level)&lt;/li&gt;
&lt;li&gt;Round 3: Friday, Nov 3, 11:15 AM , Skagit 4 (TCC Lower Level)&lt;/li&gt;
&lt;li&gt;Final : Friday, Nov 3, 3:30 PM , Skagit 4 (TCC Lower Level)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PASS Summit hosts its 4th annual Speaker Idol - Twelve contestants will have the opportunity to test their speaking skills and compete for a guaranteed session at PASS Summit 2018. Judged by an expert panel, speakers will have the chance to not only get great real time feedback and exposure to an audience from around the world, but also the opportunity to improve as speakers.&lt;/p&gt;
&lt;p&gt;Help support and cheer on your PASS Summit speakers in the making at this event open to all attendees!&lt;/p&gt;
&lt;h2 id="check-out-the-full-conference-schedule"&gt;Check out the full conference schedule&lt;/h2&gt;
&lt;p&gt;See the &lt;a href="http://www.pass.org/summit/2017/Sessions/Schedule.aspx"&gt;full schedule here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope to see you in Seattle!&lt;/p&gt;</description></item><item><title>The Death of SQL Server Service Packs</title><link>https://kendralittle.com/2017/10/06/the-death-of-sql-server-service-packs/</link><pubDate>Fri, 06 Oct 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/10/06/the-death-of-sql-server-service-packs/</guid><description>&lt;p&gt;SQL Server Service Packs are going away, starting with SQL Server 2017. I talk about why I think this is a good thing, and discuss Cumulative Updates, Service Packs, and the process of updating SQL Server.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: Listen in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WoPFBiUKz30?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Robots drafted this transcript.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Welcome to &amp;ldquo;Dear SQL DBA,&amp;rdquo; a podcast and YouTube show for SQL Server developers and database administrators. I&amp;rsquo;m Kendra little.&lt;/p&gt;
&lt;h2 id="today-were-talking-about-the-death-of-sql-server-service-packs"&gt;Today we&amp;rsquo;re talking about the death of SQL Server Service Packs&lt;/h2&gt;
&lt;p&gt;SQL Server is no longer going to have Service Packs for SQL Server 2017 and future versions.&lt;/p&gt;
&lt;p&gt;Service Packs are going away, but for your existing, older versions of SQL Server you&amp;rsquo;re still going to have Service Packs, just like before. This change is for SQL Server 2017, which just hit general availability, and future versions.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re still going to get fixes for SQL Server, it&amp;rsquo;s just that the support cycle isn&amp;rsquo;t going to include Service Packs.&lt;/p&gt;
&lt;h2 id="i-think-this-is-a-great-change-and-im-really-glad"&gt;I think this is a great change and I&amp;rsquo;m really glad!&lt;/h2&gt;
&lt;p&gt;I will not miss Service Packs.&lt;/p&gt;
&lt;p&gt;I know that people are used to them, I know that it&amp;rsquo;s a change, but I think that it&amp;rsquo;s a really positive change. We will still have Cumulative Updates.&lt;/p&gt;
&lt;h2 id="cumulative-updates-used-to-be-kind-of-confusing-and-weird"&gt;Cumulative Updates used to be kind of confusing and weird&lt;/h2&gt;
&lt;p&gt;The old story was: years ago when Microsoft released these bundles of fixes called Cumulative Updates for SQL Server, they have this little note on them that read, &amp;ldquo;you should only install this Cumulative Update if it fixes a problem that you have. We don&amp;rsquo;t generally recommend applying these all the time.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This was kind of a weird thing, because when you read the release notes for Cumulative Updates, you see that these fixes are for lots of different issues in the SQL Server. A lot of times you read these issues for fixes and you say, &amp;ldquo;well we don&amp;rsquo;t want to have that problem&amp;hellip; I am not SURE that we&amp;rsquo;ve had that problem.. but we certainly don&amp;rsquo;t want to hit it!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This would put you in kind of an odd situation, because things could go wrong! You&amp;rsquo;d want to be proactive and install the Cumulative update, because, hey, say you DO hit the problem. Then you&amp;rsquo;re like, &amp;ldquo;well, I happen to know that&amp;rsquo;s fixed by a patch.&amp;rdquo; Shouldn&amp;rsquo;t you have applied the patch to prevent it? Right?&lt;/p&gt;
&lt;h2 id="things-changed-and-cumulative-updates-are-now-much-more-clear"&gt;Things changed, and Cumulative Updates are now much more clear&lt;/h2&gt;
&lt;p&gt;The current story for Cumulative Updates&amp;ndash; and this is for your existing version of SQL Server, this isn&amp;rsquo;t just SQL Server 2017&amp;ndash; now if you look at Microsoft&amp;rsquo;s guidance on Cumulative Updates, they say: we test these a lot, we test these hard, and we think you should test them too. (Because with anything you need to test it.)&lt;/p&gt;
&lt;p&gt;But they say you should proactively test and regularly apply Cumulative Updates for your SQL Server instance, which is great.&lt;/p&gt;
&lt;p&gt;You do want to be proactive, and you don&amp;rsquo;t want to be in the position of hitting bugs and then find out that it was released in a Cumulative Update months ago.&lt;/p&gt;
&lt;p&gt;So Microsoft &amp;ndash; &lt;a href="https://blogs.msdn.microsoft.com/sqlreleaseservices/announcing-updates-to-the-sql-server-incremental-servicing-model-ism/"&gt;and this was about a year ago that they updated things&lt;/a&gt; &amp;ndash; said these Cumulative Updates are well tested and they should be part of your patching cycle.&lt;/p&gt;
&lt;h2 id="whats-it-like-to-regularly-apply-cumulative-updates"&gt;What&amp;rsquo;s it like to regularly apply Cumulative Updates?&lt;/h2&gt;
&lt;p&gt;Now the truth is, DBA teams that I&amp;rsquo;ve been on, even back in the SQL Server 2005 days I remember regularly testing and applying Cumulative Updates.&lt;/p&gt;
&lt;p&gt;What we would do is this: we would go through a testing process using development instances and pre-production instances. We&amp;rsquo;d have known versions of Cumulative Updates that had been through the testing cycle before they moved to production. We would not move EVERY Cumulative update into production, just because the amount of testing that we put them through, but we would frequently move to, &amp;ldquo;ok we&amp;rsquo;ve gone through and tested through this version of the Cumulative update, and it is safe for us.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;We would review every Cumulative update that came out, and at times would see mention of issues in there which were critical, like, okay we should get this into the testing cycle quickly, because it sounds like something we&amp;rsquo;d really want to avoid.&lt;/p&gt;
&lt;p&gt;But we wouldn&amp;rsquo;t necessarily deploy every version of Cumulative Update.&lt;/p&gt;
&lt;p&gt;What you choose to do, the frequency that you choose to test and deploy Cumulative Updates, is totally up to you&amp;ndash; but Microsoft really encourages you to not wait for Service Packs on your current versions of SQL Server before you apply changes.&lt;/p&gt;
&lt;h2 id="ever-been-trapped-between-a-cu-and-an-sp"&gt;Ever been trapped between a CU and an SP?&lt;/h2&gt;
&lt;p&gt;Part of the reason that I won&amp;rsquo;t miss Service Packs is, for these current versions of SQL Server where we have Cumulative Updates and Service Packs, you can get into weird positions with them.&lt;/p&gt;
&lt;p&gt;Sometimes a bug can be detected and fixed in a Cumulative Update that then doesn&amp;rsquo;t end up in the Service Pack based on timing.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know if you&amp;rsquo;ve ever been in the situation where you&amp;rsquo;re stuck between a Cumulative Update and a Service Pack, but we&amp;rsquo;ve had a couple of instances of this.&lt;/p&gt;
&lt;p&gt;Something, a bug, was confirmed by Microsoft, and it wasn&amp;rsquo;t confirmed in time to make the Service Pack release train. But it did make a Cumulative update release train. So you&amp;rsquo;d get into this situation where if you installed the Service Pack, you weren&amp;rsquo;t protected from the bug. If you installed the Cumulative Update, technically lower than the Service Pack, you&amp;rsquo;d be protected from the bug.&lt;/p&gt;
&lt;p&gt;What would happen in those situations is usually Microsoft would shortly release a hotfix or a patch to the Service Pack if the bug was important enough. Then you&amp;rsquo;d finally get out of this situation. But it is just weird and awkward.&lt;/p&gt;
&lt;h2 id="without-service-packs-the-service-lifecycle-for-2017-not-refers-to-cumulative-update"&gt;Without Service Packs, the service lifecycle for 2017 not refers to Cumulative Update&lt;/h2&gt;
&lt;p&gt;There are some things that had to be changed, like the the rules about the servicing life cycle for Microsoft.&lt;/p&gt;
&lt;p&gt;How old can your SQL Server instance get and still be supported by Microsoft? Questions like that.&lt;/p&gt;
&lt;p&gt;Those rules had to do with, &amp;ldquo;how how long ago was the latest Service Pack you released?&amp;rdquo; So those have been updated for SQL Server 2017, they&amp;rsquo;ve been updated to refer to the Cumulative Update lifecycle now. There still is a support lifecycle, it&amp;rsquo;s shifting to be specific to the Cumulative Updates.&lt;/p&gt;
&lt;h2 id="who-will-miss-service-packs-probably-change-approvers"&gt;Who will miss Service Packs? Probably Change Approvers.&lt;/h2&gt;
&lt;p&gt;I personally won&amp;rsquo;t miss Service Packs. This will, for those change approvers, for folks who&amp;rsquo;ve been around in IT for a while and are wary, who are like, &amp;ldquo;we don&amp;rsquo;t move to a version of SQL Server until SP1 is out&amp;rdquo; &amp;ndash; for those folks, you need to figure out: what&amp;rsquo;s the equivalent?&lt;/p&gt;
&lt;p&gt;If we don&amp;rsquo;t technically have a Service Pack, is 6 months of Cumulative Updates good enough?&lt;/p&gt;
&lt;p&gt;Because Microsoft has announced ok for 2017 we aren&amp;rsquo;t going to have Service Packs we are going to release Cumulative Updates on a given schedule. We&amp;rsquo;re going to do it once a month, I think, for the first year. They even give a date for it within the month. And then after that it goes through a different cycle. (&lt;a href="https://blogs.msdn.microsoft.com/sqlreleaseservices/announcing-the-modern-servicing-model-for-sql-server/"&gt;Read the details on the SQL Server Release Services blog here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;So you can say, at the six-month point, we should have six Cumulative Updates. At what point do they feel comfortable?&lt;/p&gt;
&lt;p&gt;These days things are really changing, and I think there&amp;rsquo;s even more to think about rather than just general availability for the boxed product. For SQL Server 2017, many of the features were available in Azure SQL database before we had general availability of the boxed product. So do you start the six months from the point at which people could raise their compat level in Azure SQL Database? It&amp;rsquo;s really up to you.&lt;/p&gt;
&lt;p&gt;I do think that it&amp;rsquo;s good for everyone if we start phasing this into our environments early. One way to think about this, if you have multiple SQL Servers, is phasing it in on our development instances and our least critical production instance first. Getting really comfortable with it, then going on our more critical instances later. Depending on how you do your licensing, what your options are will vary, of course.&lt;/p&gt;
&lt;p&gt;But I do think, yes, there is the change approver who has to adjust if there aren&amp;rsquo;t any Service Packs &amp;ndash; let&amp;rsquo;s reconsider when we deploy. I honestly think that&amp;rsquo;s a good thing, because I don&amp;rsquo;t believe in waiting for Service Pack 1, personally, to deploy.&lt;/p&gt;
&lt;p&gt;Now is a good time to review your patching and your upgrade process, and I think it&amp;rsquo;s a celebration!&lt;/p&gt;
&lt;p&gt;Enjoy the fact that Service Packs won&amp;rsquo;t always be part of our world and that with the life cycle of SQL Server 2017 we can say goodbye to Service Packs.&lt;/p&gt;
&lt;h2 id="a-quick-shout-out-to-all-of-you-who-left-a-review-for-dear-sql-dba-on-itunes"&gt;A quick shout out to all of you who left a review for Dear SQL DBA on iTunes&lt;/h2&gt;
&lt;p&gt;Your star ratings and your reviews really really help the podcast. I very much appreciate it. Also, for folks who&amp;rsquo;ve left reviews on the free courses at SQLWorkbooks.com, thank you folks so much. That really helps me build the business, and it helps me continue.&lt;/p&gt;
&lt;p&gt;Please consider leaving me a review &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;for the podcast on iTunes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks, folks and I&amp;rsquo;ll see you next week.&lt;/p&gt;</description></item><item><title>IO Patterns for Index Seeks: There May be a Lot of Read Ahead Reads</title><link>https://kendralittle.com/2017/10/04/io-patterns-for-index-seeks-there-may-be-a-lot-of-read-ahead-reads/</link><pubDate>Wed, 04 Oct 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/10/04/io-patterns-for-index-seeks-there-may-be-a-lot-of-read-ahead-reads/</guid><description>&lt;p&gt;I received a question recently asking about disk access patterns for index seeks in SQL Server. The question suggested that index seeks would have a random read pattern.&lt;/p&gt;
&lt;p&gt;Is this necessarily the case?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/squirrel-vacuum.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="index-seeks-arent-necessarily-a-small-read"&gt;Index seeks aren&amp;rsquo;t necessarily a small read&lt;/h2&gt;
&lt;p&gt;We tend to think of an index seek as a small, efficient retrieval of a few pages. It &amp;ldquo;seeks&amp;rdquo; straight there.&lt;/p&gt;
&lt;p&gt;But this isn&amp;rsquo;t necessarily the case. Seeks can read quite a large amount of data &amp;ndash; even all the data in a table if it meets the criteria for the key that I&amp;rsquo;m seeking on.&lt;/p&gt;
&lt;p&gt;Seeks may also be more complex than they sound: they may seek on &lt;em&gt;one&lt;/em&gt; key of the index, and then use non-seekable predicates to check every row that comes back to apply more filters.&lt;/p&gt;
&lt;h2 id="lets-look-at-an-example"&gt;Let&amp;rsquo;s look at an example&lt;/h2&gt;
&lt;p&gt;I have a table named dbo.FirstNameByBirthDate, which has a row for each baby name reported in the United States from 1880 to 2015.&lt;/p&gt;
&lt;p&gt;There is a nonclustered index on a column named BirthYear.&lt;/p&gt;
&lt;p&gt;I run the following query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1700&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="it-gets-a-seek"&gt;It gets a seek!&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the plan for the query. This gets a seek operator&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/it-gets-a-seek-plan-1024x86.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Digging into the properties of that operator, the seek predicate here is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Seek Keys[1]: Start: [BabbyNames201711].[dbo].[FirstNameByBirthDate].BirthYear &amp;gt; Scalar Operator([@1])&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SQL Server knows this is going to be a lot of rows. It decides to go parallel.&lt;/p&gt;
&lt;p&gt;Having checked the data, I know that this seek operation is going to read the entire index on BirthYear. But, technically, this is still a seek operation.&lt;/p&gt;
&lt;h2 id="what-types-of-read-operations-does-this-do"&gt;What types of read operations does this do?&lt;/h2&gt;
&lt;p&gt;Looking at an actual execution plan, I dig into the index seek operator and it shows me information about the physical IO. Almost all of the requests were read-ahead reads.&lt;/p&gt;
&lt;p&gt;Read-ahead is a mechanism that SQL Server can use when it&amp;rsquo;s pulling a lot of information from disk. Instead of pulling 8K pages onesy-twosy-threesy, SQL Server can suck up big chunks of pages from disk with a vacuum cleaner.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re running developer or enterprise edition, you may get a larger vacuum cleaner.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/read-ahead-reads-index-seek.png"&gt;
&lt;/figure&gt;
&lt;h2 id="what-does-that-look-like-to-windows"&gt;What does that look like to Windows?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a couple of ways to look at the read size. One method is to fire up the SysInternals tool &lt;a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procmon"&gt;Process Monitor&lt;/a&gt; and watch ReadFile operations from sqlservr.exe on a test system.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a sample of the reads it saw when I was doing this seek (and not running anything else on the instance). The highlighted row has a length of 524,288 - that&amp;rsquo;s a 512KB read! I&amp;rsquo;m running Developer Edition, so I&amp;rsquo;ve got the big read-ahead vacuum cleaner.&lt;/p&gt;
&lt;p&gt;Most of the reads here are 64K chunks, but there&amp;rsquo;s quite a few cases when it can grab more&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/readfile-sqlservr-1024x303.png"&gt;
&lt;/figure&gt;
&lt;em&gt;A small excerpt of the read operations seen by Process Monitor&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-does-this-mean"&gt;What does this mean?&lt;/h2&gt;
&lt;p&gt;This means that there&amp;rsquo;s no simple shortcut to establishing and testing IO patterns for an application.&lt;/p&gt;
&lt;p&gt;You shouldn&amp;rsquo;t, for instance, look at a performance counter that says there&amp;rsquo;s a lot of index seeks and interpret that to mean that there&amp;rsquo;s a lot of tiny 8K random read operations going to disk. Index seeks just aren&amp;rsquo;t that simple, and that&amp;rsquo;s a good thing for performance! Even if seeks do need to go to disk, they are able to leverage read-ahead reads &amp;ndash; and they may be &amp;lsquo;seeking&amp;rsquo; a lot of data.&lt;/p&gt;
&lt;p&gt;If you want to get into the nitty gritty and collect data to help you characterize your workload, check out the &lt;a href="https://technet.microsoft.com/en-us/library/ee410782.aspx"&gt;Analyzing I/O Characteristics and Sizing Storage Systems for SQL Server&lt;/a&gt; whitepaper.&lt;/p&gt;
&lt;p&gt;And I guess I should admit: read-ahead doesn&amp;rsquo;t really use a vacuum cleaner.&lt;/p&gt;</description></item><item><title>Love and Hate for SSMS</title><link>https://kendralittle.com/2017/09/29/love-and-hate-for-ssms/</link><pubDate>Fri, 29 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/29/love-and-hate-for-ssms/</guid><description>&lt;p&gt;People have strong feelings about SQL Server Management Studio: they love it AND they hate it. In this week&amp;rsquo;s episode, I talk about why people have such conflicting feelings about SSMS, and how to work it all out.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now or read the transcript below? Listen in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/7tsx0i4rABA?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;Hello and welcome to Dear SQL DBA, a podcast and YouTube show for SQL Server developers and database administrators. I&amp;rsquo;m Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;m going to talk about what people love and what people hate about SQL Server Management Studio. I&amp;rsquo;m not going to get super technical today, I&amp;rsquo;m just going to dish a little bit about Management Studio and why people feel really strongly about it.&lt;/p&gt;
&lt;p&gt;The question that inspired this episode is this: I was giving a webcast on shortcuts and secrets for using Management Studio, and one of the very first questions that came in before the webcast even started was:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why does Management Studio crash so much?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve had Management Studio crash on me plenty of times in the past, too, so let&amp;rsquo;s talk.&lt;/p&gt;
&lt;h2 id="configurable-vs-confusing"&gt;Configurable vs. confusing&lt;/h2&gt;
&lt;p&gt;People love that SQL Server Management Studio is so configurable and the &lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;shortcuts and secrets&lt;/a&gt; webcast that I gave&amp;ndash; it contains a lot of all of the ways you can customize Management Studio. Also, how to do some things that it might not be obvious that you can even do them in a faster way.&lt;/p&gt;
&lt;p&gt;But one of the reasons that people also really can dislike Management Studio is that they find it really confusing. This is related to why people have really strong feelings about Management Studio: because there&amp;rsquo;s a pretty strong learning curve. There&amp;rsquo;s a ton of things that you can do in SQL Server Management Studio and it&amp;rsquo;s very very highly configurable, but to a level that that actually makes it pretty confusing!&lt;/p&gt;
&lt;p&gt;Sometimes I get into a situation myself where &amp;ndash; I&amp;rsquo;ve been using this thing for many many years since it came out with SQL Server 2005, back in the day. I remember when Management Studio first came out, I was like, &amp;quot; I don&amp;rsquo;t know if I like this thing!&amp;quot; Because I was very comfortable with the old tools. Even now, sometimes there will be a setting that I&amp;rsquo;m looking for, and just finding it can be pretty tricky. There&amp;rsquo;s even a little &amp;ldquo;find&amp;rdquo; bar in the settings where you can search for a given setting &amp;ndash; under tools / options, when you&amp;rsquo;re going into the different things you can configure 00 and sometimes that &amp;ldquo;find&amp;rdquo; bar doesn&amp;rsquo;t even find me what I&amp;rsquo;m looking for.&lt;/p&gt;
&lt;p&gt;To make the best of this, what I do and what a lot of people do is: I have a setup checklist for SQL Server Management Studio that I like to use. When I&amp;rsquo;m configuring Management Studio I have a list I can run off: these are the things that give me what I want to set Management Studio up to my preferences, because preferences do differ.&lt;/p&gt;
&lt;h2 id="having-a-setup-list-helps-you-remember-what-management-studio-doesnt-do-by-default"&gt;Having a setup list helps you remember what Management Studio doesn&amp;rsquo;t do by default&lt;/h2&gt;
&lt;p&gt;I have worked in some situations as a consultant where I&amp;rsquo;m not connecting to things always from my version of Management Studio. I&amp;rsquo;m looking remotely at someone else&amp;rsquo;s computer, and I&amp;rsquo;m using their Management Studio set up.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s not always cool to just change someone&amp;rsquo;s setup.&lt;/p&gt;
&lt;p&gt;Having the setup checklist helps - even if I&amp;rsquo;m not going to run through it, knowing what&amp;rsquo;s on my list of things that I change sets me up to expect, &amp;ldquo;ok I know the items that aren&amp;rsquo;t going to be normal to me because they are the things that I typically change.&amp;rdquo; I can tell for instance: I&amp;rsquo;m using someone else&amp;rsquo;s install of Management Studio, if I script out indexes and the indexes are compressed, it&amp;rsquo;s not going to script out the data compression settings, because that that&amp;rsquo;s not configured by default. I know what to look for if I&amp;rsquo;m going to do certain things. (My setup list is included in my &lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;free course on SSMS Shortcuts &amp;amp; Secrets&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="shortcuts-are-awesome-but-a-bit-overwhelming"&gt;Shortcuts are awesome! But a bit overwhelming&lt;/h2&gt;
&lt;p&gt;One of the other things that people love about Management Studio&amp;ndash; I love this too&amp;ndash; is that there&amp;rsquo;s a lot of shortcuts, and you can configure a lot of your own shortcuts.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t have to reach the mouse super often. You can keep your hands on the keyboard in Management Studio.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s great, and when you&amp;rsquo;re in the flow and you&amp;rsquo;re using a lot of the keyboard shortcuts, it just feels really cool. It feels really good: there&amp;rsquo;s something about that flow of being able to do a lot of things on the keyboard that is fun. But there&amp;rsquo;s also the fact that it&amp;rsquo;s hard to remember all of these shortcuts.&lt;/p&gt;
&lt;p&gt;Even shortcuts that you know pretty well, if you don&amp;rsquo;t use them for a while and then you go back, you&amp;rsquo;re like, &amp;ldquo;oh wait, how did I do that thing again?&amp;rdquo; The muscle memory is gone.&lt;/p&gt;
&lt;p&gt;To learn shortcuts, what I like to do is to practice them in small groups. I found that I don&amp;rsquo;t do super well learning lots of shortcuts at once. Instead, I like to have a list of them &amp;ndash; and I put this together with my setup checklist in my free course on Management Studio Shortcuts and Secrets &amp;ndash; and I not only have the list of things I like to configure, but I keep a list of shortcuts there too.&lt;/p&gt;
&lt;p&gt;I like to periodically review them and practice using them. Because even even shortcuts I kind of know, if I&amp;rsquo;m not in the habit of using them, I don&amp;rsquo;t remember them. So I&amp;rsquo;ll periodically look through the list and be like, &amp;ldquo;oh yeah, I should get back to using this shortcut on the keyboard to get me down to the results pane, so that I don&amp;rsquo;t just grab the mouse every time I want to go down to the results pane,&amp;rdquo; for for example. (That&amp;rsquo;s F6, by the way.)&lt;/p&gt;
&lt;p&gt;My favorite shortcuts these days are using the little IDE that you can use to switch between sessions. If you do ctrl + tab it brings up this little display and hitting ctrl + tab iterates you through all of your Management Studio sessions. You can easily switch between what you&amp;rsquo;ve got open. If you do alt + f7 that brings up the same IDE, but lets you switch over to tools like Object Explorer, and things like that. You can actually arrow around when you bring it up with alt + f7, say if you are on Object Explorer and then you want to switch back to a session. Alt + f7 is really flexible - I don&amp;rsquo;t love it because on some keyboards I have to hit a function key - I have to hit &amp;ldquo;fn&amp;rdquo; to be able to use a function keys, so control tab works on more of my keyboards and is easier. I just I can&amp;rsquo;t get enough of that switching between sessions. It&amp;rsquo;s a lot like the Windows alt + tab, but within Management Studio for your sessions.&lt;/p&gt;
&lt;h2 id="people-also-love-the-flexibility-of-management-studio"&gt;People also love the flexibility of Management Studio&lt;/h2&gt;
&lt;p&gt;It does so many things. When you think about all of the different things&amp;ndash; there&amp;rsquo;s a wizard you can open that scripts out all the objects in the database. There&amp;rsquo;s security you can configure. There&amp;rsquo;s objects you can create. I mean, there&amp;rsquo;s just so many little tools in Management Studio, and it&amp;rsquo;s even getting bigger. Right now we have an Extended Events GUI within Management Studio, whereas ye old SQL Profiler &amp;ndash; there used to be a shortcut to it, and I guess there still is, you can open it from Management Studio, but it&amp;rsquo;s another application.&lt;/p&gt;
&lt;p&gt;Management Studio is getting more and more integrated as this giant Swiss Army knife, but there&amp;rsquo;s always things that people dislike that it&amp;rsquo;s missing.&lt;/p&gt;
&lt;p&gt;One thing I found is that certain things that I thought Management Studio didn&amp;rsquo;t do are in there! I just didn&amp;rsquo;t know how to get to them. A lot of these&amp;ndash; for example, the scripting options I was talking about.&lt;/p&gt;
&lt;p&gt;I thought for a long time that Management Studio just Couldn&amp;rsquo;t script out certain things if you&amp;rsquo;re scripting a partitioned index. That it just wouldn&amp;rsquo;t script out the filegroup that it&amp;rsquo;s on&amp;ndash; or wait, that&amp;rsquo;s not it, it&amp;rsquo;s the partition scheme that it&amp;rsquo;s created on.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s actually like the compression settings: that&amp;rsquo;s one of the options you can configure. There&amp;rsquo;s whole series of settings for how things get scripted out under Tools / Options. There&amp;rsquo;s a whole scripting section for Object Explorer.&lt;/p&gt;
&lt;p&gt;I just didn&amp;rsquo;t know it existed. I didn&amp;rsquo;t find out that it existed until tweeted about this: &amp;ldquo;is this a bug that it doesn&amp;rsquo;t script out _____?&amp;rdquo; And Adam Machanic answered: &amp;ldquo;it does that, and here&amp;rsquo;s where it is.&amp;rdquo; Lo and behold, the things that I thought were missing were actually there.&lt;/p&gt;
&lt;p&gt;If you do have things where you&amp;rsquo;re like, &amp;ldquo;I really think it should do this differently,&amp;rdquo; you can file a suggestion or a bug at &lt;a href="https://connect.microsoft.com/SQLServer"&gt;https://connect.microsoft.com/SQLServer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the ones that I&amp;rsquo;ve seen recently is when you drag over the all the column names &amp;ndash; you&amp;rsquo;re dragging over the columns &lt;em&gt;&lt;strong&gt;folder&lt;/strong&gt;&lt;/em&gt;, rather: in Object Explorer you can grab the column folder for a table and drag that column folder over, and it will auto-populate the names of all of the columns in a comma delimited list in your session. But it doesn&amp;rsquo;t put the square brackets around the column names. If you drag over the table name it will put safety brackets around the table name, so if you have any weird characters in there everything still works. So there&amp;rsquo;s an inconsistency between what you drag over from Object Explorer to your window, and someone filed &amp;ndash; I can&amp;rsquo;t remember if it was a bug or a suggestion &amp;ndash; but basically, &amp;ldquo;plz make it consistent.&amp;rdquo; The developer looked at this and was like, &amp;ldquo;oh yeah, we can totally fix that.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I believe that the fix hasn&amp;rsquo;t been released yet, but the code for the the bug is in the &amp;ldquo;completed&amp;rdquo; state. I don&amp;rsquo;t think that release for Management Studio is out now, but I can&amp;rsquo;t remember. (I&amp;rsquo;m like, &amp;ldquo;did that happen the last time I tested it?&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;But filing a Connect item got things changed and got things fixed. That&amp;rsquo;s one of the cool things: if you want it to be different, first of all ask on Twitter and see, &amp;ldquo;is it actually there and I just don&amp;rsquo;t know about it?&amp;rdquo; But also, Microsoft is open to knowing what do you want this thing to do, and how can we do things better.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: &lt;a href="https://connect.microsoft.com/SQLServer/Feedback/Details/3120203"&gt;this is the Connect item&lt;/a&gt;, and I just re-tested and indeed the change is active in SSMS 14.0.17177.0. I see [column names with brackets] after dragging over a 'columns' folder.
&lt;/div&gt;
&lt;h2 id="your-change-could-become-reality-because-ssms-gets-frequent-updates-these-days"&gt;Your change could become reality! Because SSMS gets frequent updates these days&lt;/h2&gt;
&lt;p&gt;I really love how active the Management Studio coding team has become. For Management Studio, it used to be that we only got updates when SQL Server got updated. Now Management Studio releases on its own, and this is fantastic because they can release as often as they&amp;rsquo;re ready to release. When we update Management Studio, we can choose: do we want to update it on the production server at all? Or do we just want to update it on our client machines now, and maybe update Management Studio more quickly on our client machines than we would on the production Server itself, where we may not want to reboot every time we just have an update to Management Studio.&lt;/p&gt;
&lt;p&gt;There are still folks who are afraid to upgrade for a variety of reasons. If I&amp;rsquo;m running a new version of Management Studio, is everything going to work? This is valid! With any software, when things change, sometimes things break. There was a recent version of Management Studio where if you were connecting to a case-sensitive instance, there were certain graphical elements that didn&amp;rsquo;t work as they had before.&lt;/p&gt;
&lt;p&gt;The good news is you can choose how you update Management Studio, in the sense of how many versions of Management Studio you have. This is particularly useful with major versions of Management Studio. We recently had just a big major version come out, and with Management Studio you can do side by side installations.&lt;/p&gt;
&lt;p&gt;So you can do things like say: ok I&amp;rsquo;m going to try out the new version on my client computer, but if anything&amp;rsquo;s weird I can you know run a version on a different machine that&amp;rsquo;s older.&lt;/p&gt;
&lt;p&gt;But you can ALSO install side by side on your computer the latest and greatest and keep the old one there if you want to go back even the last major version. &amp;ldquo;I&amp;rsquo;m going to just keep this last major version of it around for a while. It doesn&amp;rsquo;t have the new look and feel, and it doesn&amp;rsquo;t have some of the cool things in the new version, but for accomplishing basic tasks it&amp;rsquo;s my old faithful.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;You can keep that old version around for a really long time, and that lets you say, &amp;ldquo;okay, I&amp;rsquo;m only going to use the new updated SSMS against our dev instances. I still have my older version to use against production.&amp;rdquo; You can be as careful as you want to be, which i think is terrific.&lt;/p&gt;
&lt;p&gt;And always, always, test against development, and update on your workstation before you ever go and touch things on the production server.&lt;/p&gt;
&lt;h2 id="theres-so-much-great-community-content-on-using-ssms"&gt;There&amp;rsquo;s so much great community content on using SSMS&lt;/h2&gt;
&lt;p&gt;One of the things that I can&amp;rsquo;t get enough of is that lots of people in the community document things for SSMS. They create their checklists for &amp;ldquo;here&amp;rsquo;s the things I change in SSMS,&amp;rdquo; and they also mention and create presentations for their favorite shortcuts and their tips and tricks. I can&amp;rsquo;t get enough of those sessions. I seriously would watch one a week or maybe even more often if there were a ton of them out there.&lt;/p&gt;
&lt;p&gt;On the other hand, there is a lot of community participation because it&amp;rsquo;s so complicated.&lt;/p&gt;
&lt;p&gt;There may be times where something you see in a presentation, and you try to do it, and it doesn&amp;rsquo;t work for you. Maybe that&amp;rsquo;s because you&amp;rsquo;re connected through a VM and something&amp;rsquo;s overriding a key in the shortcut you&amp;rsquo;re trying to use. Or maybe it&amp;rsquo;s for another reason.&lt;/p&gt;
&lt;h2 id="so-lets-talk-about-that-crashing-problem"&gt;So let&amp;rsquo;s talk about that crashing problem&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s get back to the original question that inspired me to put this together. It was, &amp;ldquo;why does my Management Studio crash so much?&amp;rdquo; This is similar to, &amp;ldquo;why doesn&amp;rsquo;t X feature work for me in Management Studio?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;One of the first things to just check is what version of Management Studio are you running? How old is it? You may be hitting a bug in an older version of Management Studio. It might be a bug that causes it to crash, or it might be a bug where just some things didn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;For example, one of my favorite shortcuts is ctrl + u. It takes you up to the &amp;ldquo;use database&amp;rdquo; box. I&amp;rsquo;ve had some folks be like, &amp;ldquo;it just doesn&amp;rsquo;t work for me.&amp;rdquo; Well, there was a bug in an older version of Management Studio that was &amp;ldquo;ctrl + u doesn&amp;rsquo;t work.&amp;rdquo; For some of these folks, updating Management Studio fixed it.&lt;/p&gt;
&lt;p&gt;Some of the crashing bugs are from older versions as well.&lt;/p&gt;
&lt;p&gt;Also, are you using a plugin, or are you connecting via a virtual machine that could be causing the problem?&lt;/p&gt;
&lt;p&gt;Some of the cases I&amp;rsquo;ve had where ctrl + u wasn&amp;rsquo;t working for people was actually caused by the fact that they were using a plugin that had broken ctrl + u as well! You&amp;rsquo;ve got to test out, &amp;ldquo;what do I have installed that isn&amp;rsquo;t from Microsoft, that&amp;rsquo;s extra in here, and could it be causing the problem as well?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Sometimes it might be also that of course your virtual machine provider thinks that keyboard shortcut really means something else, too.&lt;/p&gt;
&lt;p&gt;If you are seeing repeated crashing, and it isn&amp;rsquo;t any of these things, have you reported it to Microsoft? Because you should report it to Microsoft! If Management Studio is crashing out all the time, they don&amp;rsquo;t want that to happen. Use sites like &lt;a href="https://connect.microsoft.com/SQLServer"&gt;connect.microsoft.com/SQLServer&lt;/a&gt; if you&amp;rsquo;re getting a specific error message. If the crash is happening when you do a given sequence of tasks, you can let the developers know about that as well.&lt;/p&gt;
&lt;p&gt;So do something about it!.&lt;/p&gt;
&lt;p&gt;And please please please PLEASE share the things that you love doing in Management Studio. The tips and tricks that you know that make using it easier and more fun. Like I said, I really can&amp;rsquo;t get enough of that stuff. I would love to have even more shortcut cheat sheets be out there, and even more checklists of how to get more out of your day with Management Studio.&lt;/p&gt;
&lt;p&gt;Because, like you, I spend an awful lot of time in Management Studio, and the more fun I have, the more fun my day is!&lt;/p&gt;
&lt;p&gt;Thanks for joining me for Dear SQL DBA this week. I&amp;rsquo;m Kendra Little, and I&amp;rsquo;ll see you again soon.&lt;/p&gt;</description></item><item><title>New Free Webcasts for November and December 2017</title><link>https://kendralittle.com/2017/09/28/new-free-webcasts-for-november-and-december-2017/</link><pubDate>Thu, 28 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/28/new-free-webcasts-for-november-and-december-2017/</guid><description>&lt;h2 id="ive-just-scheduled-a-whole-batch-o-free-webcasts"&gt;I&amp;rsquo;ve Just Scheduled a Whole Batch o&amp;rsquo; Free Webcasts!&lt;/h2&gt;
&lt;p&gt;Webcasts are held on Thursdays at 9 AM Pacific / noon Eastern / 4 pm UTC.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the upcoming slate of topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Oct 5 – RCSI and Snapshot Isolation&lt;/li&gt;
&lt;li&gt;Oct 19 – Pressure Testing Memory&lt;/li&gt;
&lt;li&gt;Oct 26 – What’s REALLY in That Index?&lt;/li&gt;
&lt;li&gt;Nov 9 – Filtered Columnstore Indexes&lt;/li&gt;
&lt;li&gt;Nov 16 – Defragging: Reorg or Rebuild?&lt;/li&gt;
&lt;li&gt;Nov 30 – In-Memory Indexes &amp;amp; Isolation&lt;/li&gt;
&lt;li&gt;Dec 7 – Indexing for Windowing Functions&lt;/li&gt;
&lt;li&gt;Dec 14 – Serializable &amp;amp; Repeatable Read&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can&amp;rsquo;t wait to put together these presentations, and I hope to see you on Thursdays!&lt;/p&gt;</description></item><item><title>How Do I Analyze a SQL Server Execution Plan?</title><link>https://kendralittle.com/2017/09/22/how-do-i-analyze-a-sql-server-execution-plan/</link><pubDate>Fri, 22 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/22/how-do-i-analyze-a-sql-server-execution-plan/</guid><description>&lt;p&gt;A query is slow, and you figure out how to collect the query execution plan. Now what?&lt;/p&gt;
&lt;p&gt;In this video, I talk &amp;ldquo;big picture&amp;rdquo; about what execution plans are, what &amp;ldquo;cost&amp;rdquo; is, why to collect &amp;ldquo;compiled for&amp;rdquo; values, and the steps I take to analyze execution plans while performance tuning queries.&lt;/p&gt;
&lt;h2 id="video-version-26-minutes"&gt;Video version (26 minutes)&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now or read the transcript below? Listen in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/ffsdA6NgGk4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Welcome to Dear SQL DBA, a podcast for SQL Server developers and database administrators. I&amp;rsquo;m Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;p&gt;This week I&amp;rsquo;m talking about a question that I recently got from a student&amp;ndash; but I&amp;rsquo;ve gotten it from different people by email over the years, too. We&amp;rsquo;re talking about how to analyze a SQL Server execution plan.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the question came in this time: a student asked, &amp;ldquo;I&amp;rsquo;ve got a terribly performing query, and I&amp;rsquo;ve collected a complex execution plan for it. But I&amp;rsquo;m not sure how to interpret valuable information from the plan. Big picture: What do i do? How do I attack this thing?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re gonna talk about this and break it down.&lt;/p&gt;
&lt;h2 id="first-up-what-is-an-execution-plan"&gt;First up: what is an execution plan?&lt;/h2&gt;
&lt;p&gt;When you submit a query to SQL Server, it needs to figure out: how am I gonna run this thing? What indexes do I want to use? Can I do seeks on them do I need to scan them? What kind of joins? If you&amp;rsquo;re joining different tables together, what kind of operations do I want to use to join these things together? Do I need to build temporary objects? Do I want to do lookup operations? Should I use multiple cores to do this or should I do it single threaded?&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a lot of different things for it to consider and the execution plan is compiled by the SQL Server query optimizer before it ever gets started running the query. SQL Server has to use things like statistics&amp;ndash; these little samples of data that help it guess, &amp;ldquo;hey how much data will I be dealing with from this particular table?&amp;rdquo; It also has to look at things in the query: if you have parameterized values it&amp;rsquo;ll try to sniff out, &amp;ldquo;hey if i have to compile a plan for this, what are the the values you&amp;rsquo;re using for the parameters for this stored procedure?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Or perhaps it&amp;rsquo;s a parameterized query. Because if you&amp;rsquo;re if you&amp;rsquo;ve got those values in a predicate and you&amp;rsquo;re limiting the rows by certain filters with those values, that influences heavily how much data is coming out of different tables involved in the query.&lt;/p&gt;
&lt;p&gt;It has to make a lot of guesses before the query ever starts executing, and SQL Server doesn&amp;rsquo;t reconsider the execution plan while the query is in mid-flight.&lt;/p&gt;
&lt;p&gt;There is a feature that&amp;rsquo;s coming to us in SQL Server 2017 where certain query plans under certain conditions will have parts of them that are quote &amp;ldquo;adaptable&amp;rdquo;. Where on later runs of the query, SQL Server might be like, &amp;ldquo;that didn&amp;rsquo;t work out so well, so I&amp;rsquo;m gonna try a different tactic just for this part of the plan,&amp;rdquo; but that&amp;rsquo;s only in certain cases and we don&amp;rsquo;t even have SQL Server 2017 yet. So as of right now with SQL Server 2016 and prior, optimization only happens before the query starts running, and it&amp;rsquo;s all based on these estimates. SQL Server doesn&amp;rsquo;t stop and think, &amp;ldquo;did the query turn out like I estimated?&amp;rdquo;&lt;/p&gt;
&lt;h3 id="execution-plans-can-be-reused"&gt;Execution plans can be reused&lt;/h3&gt;
&lt;p&gt;SQL Server doesn&amp;rsquo;t want to compile an execution plan every time that you run a query if it doesn&amp;rsquo;t have to, so it&amp;rsquo;ll look at it and say, &amp;ldquo;hey do I have a compiled plan in cache for this query, and maybe are we running it the same stored procedure or this same parameterized query &amp;ndash; are we running it with different values for the parameter?&amp;rdquo; In a lot of cases, it&amp;rsquo;ll say, &amp;ldquo;good thing I already compiled the plan for that, I&amp;rsquo;ve got it in memory. I can just reuse that execution plan.&amp;rdquo; So an execution plan is a way that SQL server guesses: given all my options, I think this is the best way to execute this query. It makes that guess before it ever starts running the query. Sometimes it&amp;rsquo;s using a guess that it compiled earlier, possibly for different parameter values.&lt;/p&gt;
&lt;h3 id="when-you-ask-why-was-the-query-slow-the-answer-is-not-always-in-the-execution-plan"&gt;When you ask, &amp;ldquo;why was the query slow?&amp;rdquo; the answer is NOT always in the execution plan&lt;/h3&gt;
&lt;p&gt;We have this additional factor in addition to everything I&amp;rsquo;ve started talking about: sometimes it query is slow for reasons that have nothing to do with the execution plan itself! Or at least that aren&amp;rsquo;t the fault of the execution plan.&lt;/p&gt;
&lt;p&gt;Maybe my query needed a lock on a resource and something else was holding that lock, and it just had to sit and wait for the lock for a really long time. Yeah, okay, the execution plan was accessing a structure that was locked, it is *kinda* related to the plan, but the cause of this is more like: &amp;ldquo;Well why was something holding that lock for a really long time?&amp;rdquo; or &amp;ldquo;What isolation levels are we using?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Those aren&amp;rsquo;t a problem with the plan. Is the issue that storage was really slow? Sometimes the query is slow for reasons entirely different from the plan, and you wouldn&amp;rsquo;t know that just from looking at the plan.&lt;/p&gt;
&lt;p&gt;Things are changing fast though: as of SQL Server 2016 Service Pack 1, certain kinds of plans called actual execution plans do you have some information about wait statistics in them. It&amp;rsquo;s only that type of plan&amp;ndash; the actual type of plan in SQL Server 2016 Service Pack 1 and later.&lt;/p&gt;
&lt;p&gt;Most of the time when we&amp;rsquo;re looking at an execution plan we don&amp;rsquo;t have that information of did the query have to wait, and if so what was it waiting on.&lt;/p&gt;
&lt;h3 id="we-usually-dont-have-information-in-the-plan-about-how-long-the-query-took"&gt;We usually don&amp;rsquo;t have information in the plan about how long the query took&lt;/h3&gt;
&lt;p&gt;Even looking at the actual execution plan, only if the SQL Server Engine &amp;ndash; not where you have management studio is, but the instance you were running the query against&amp;ndash; only in SQL Server 2014 Service Pack 2 and higher will you have information about how much CPU was used, how what was the duration, and how many reads did something&amp;rsquo;s do. Even then it&amp;rsquo;s still only those actual plans: only one type of execution plan.&lt;/p&gt;
&lt;p&gt;So how long was the query even slow?&lt;/p&gt;
&lt;p&gt;So many execution plans&amp;ndash; when you look at those most execution plans you can&amp;rsquo;t even tell how long did the whole query take, much less how long did a specific part of the query take. What all this means is that execution plans are absolutely valuable &amp;ndash; I love working with them&amp;ndash; and they make tuning queries much easier to me, but you do have to do other legwork to figure out things like were there waits in wait statistics? In other words, were there resources that the query didn&amp;rsquo;t have to execute, that impacted it, that we&amp;rsquo;re outside of the plan&amp;rsquo;s control.&lt;/p&gt;
&lt;p&gt;How long did the query take in parts and in whole? Having that extra information and figuring it out is a valuable part of interpreting the plan.&lt;/p&gt;
&lt;p&gt;I love plans I&amp;rsquo;m not putting them down, you can get tons of valuable info from them just be prepared to dig for supplementary information to help you interpret the plan, or to know if the problem can be answered in part by the plan.&lt;/p&gt;
&lt;p&gt;When I&amp;rsquo;m interpreting plans, I think about a lot of different things and I&amp;rsquo;m going to step through today just what are the types of execution plans, what is &amp;ldquo;cost&amp;rdquo; in an execution plan and how I think of it, what &amp;ldquo;compiled for&amp;rdquo; values are and why you should collect them, and then steps to interpret the plan.&lt;/p&gt;
&lt;h2 id="types-of-execution-plans"&gt;Types of execution plans&lt;/h2&gt;
&lt;h3 id="estimated-execution-plans"&gt;Estimated execution plans&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re going to run a query against SQL Server in Management Studio, you can say, give me an estimated plan for this. SQL Server will compile, &amp;ldquo;here&amp;rsquo;s what I think I would do,&amp;rdquo; without executing the query. These can be really useful because maybe your query takes 15 minutes to run you just want to get an idea of how much work do you think this is gonna be, without waiting the whole 10 minutes or using those resources.&lt;/p&gt;
&lt;p&gt;You can also see certain things in estimated plans that show up in a different way than they do in other plans: things like functions. If you look at an estimated plan, they will actually show up in a more obvious way &amp;ndash; they&amp;rsquo;ll be broken out in more detail than they are when you&amp;rsquo;re looking at what&amp;rsquo;s called an actual execution plan.&lt;/p&gt;
&lt;p&gt;Sometimes you can get a really clear insight of, &amp;ldquo;oh look at all this work involved in this function&amp;rdquo; broken out in a different way in an estimated plan when you look at that in Management Studio. But an estimated plan, is just that, &amp;ldquo;Here&amp;rsquo;s what I think I would do. Here&amp;rsquo;s how many rows I think would come back from this, here&amp;rsquo;s what index I think I would use.&amp;rdquo; We don&amp;rsquo;t know how many rows are actually gonna come back from that, so we just have information about &amp;ldquo;here&amp;rsquo;s here&amp;rsquo;s the direction I think I&amp;rsquo;d head in.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="cached-execution-plans"&gt;Cached execution plans&lt;/h3&gt;
&lt;p&gt;A lot of times when we&amp;rsquo;re troubleshooting a slow query we are working with an execution plan that we have pulled from the memory of the SQL Server because we&amp;rsquo;re looking for our top queries and we&amp;rsquo;re saying, &amp;ldquo;hey based on the information you have in memory, SQL Server,&amp;rdquo; maybe I&amp;rsquo;ve got a query where I&amp;rsquo;ve said I want to see the execution plans for the queries that have the longest duration. I pulled these plans out of cache.&lt;/p&gt;
&lt;p&gt;These cached plans can be reused, and I may have overall information on, &amp;ldquo;since this plan was put in cache, how much CPU does it take on average? What duration does it take on average?&amp;rdquo; And also things like what&amp;rsquo;s the max duration it&amp;rsquo;s taken, what&amp;rsquo;s the max CPU it&amp;rsquo;s used. I have aggregate information like that, but with this cached plan I don&amp;rsquo;t know things like &amp;ndash; okay you estimated 10 rows would come from that index, was it actually 10 or was it 10 million? The cached plan just has things like those estimated rows. It doesn&amp;rsquo;t have details on actually how many rows flowed through different parts of the plan. It doesn&amp;rsquo;t have duration information for how long different parts of the plan took.&lt;/p&gt;
&lt;p&gt;I can kind of make some guesses based on those aggregate statistics, what I know about the tables, and some testing, but again I have to do some legwork to figure out, &amp;ldquo;hey is all of this estimated stuff in the plan, does it it does have anything to do with what actually happened when the query ran?&amp;rdquo;&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: I think it was Brent Ozar who I first saw categorize cached plans as a different type than estimated plans. It may make sense to break out Query Store plans as their own type as well, as there are going to be certain nuances where they're difference from the plan in memory, especially when adaptive query plans come into play.
&lt;/div&gt;
&lt;h3 id="actual-execution-plans"&gt;Actual execution plans&lt;/h3&gt;
&lt;p&gt;These are really, really valuable, but we have to be careful generating them. One of the deals with actual execution plans is that tracing plans (any type, not just actual plans) may slow down your SQL Server a lot. Collecting them by trace is really expensive and can hurt performance.&lt;/p&gt;
&lt;p&gt;You can get them by running a query yourself, but you have to run the query yourself and sometimes that&amp;rsquo;s not ok. Sometimes we have to restore the database someplace else to be able to rerun the query, and that can take a lot of time. Sometimes if the query is modifying a bunch of data that process of running it someplace where it&amp;rsquo;s safe to run, and then resetting the environment again can be somewhat cumbersome.&lt;/p&gt;
&lt;p&gt;But actual execution plans can have a wealth of information, especially on SQL Server 2014 service pack 2 and higher where we can get things like not only how many rows flowed through different parts of the plan, but also information on how much CPU were we using at this point in the plan. It takes a little while to get used to interpreting this, because in certain operators that information is cumulative with its child operators, and in certain operators it&amp;rsquo;s not, but it&amp;rsquo;s a wealth of information for us. We also get those wait statistics in SQL Server 2016 and higher.&lt;/p&gt;
&lt;h2 id="tips"&gt;Tips&lt;/h2&gt;
&lt;h3 id="cost-is-an-estimate---even-in-actual-plans"&gt;Cost is an estimate - even in &amp;ldquo;actual&amp;rdquo; plans&lt;/h3&gt;
&lt;p&gt;Depending on knowing what type of plan we&amp;rsquo;re looking at, when interpreting a plan it&amp;rsquo;s really useful &amp;ndash; even in an actual plan &amp;ndash; one important thing to know is that when you&amp;rsquo;re looking at cost numbers they are always an estimate.&lt;/p&gt;
&lt;p&gt;Even though we call it an actual plan, an actual plan is an estimated plan that&amp;rsquo;s had some additional information added to it about things like, &amp;ldquo;okay what were our actual rows and what were certain actuals&amp;rdquo; But SQL Server doesn&amp;rsquo;t go back and readjust the cost. It wouldn&amp;rsquo;t make sense to in a lot of ways, as the cost information in the plan has to do with the reasoning behind why it chose these operators. If the cost was just sort of completely adjusted all the time, sometimes looking at a plan it would make no sense why it had done that.&lt;/p&gt;
&lt;p&gt;So I actually like that cost is always an estimate, the important thing is just to remember that and don&amp;rsquo;t fall into the trap of always just looking at the &amp;ldquo;high cost operators.&amp;rdquo; I do think it&amp;rsquo;s valuable to look for the operators that have the highest cost&amp;ndash; I will look at those in the plan. I&amp;rsquo;m gonna be like, &amp;ldquo;okay this is what SQL Server thought would be the most work.&amp;rdquo; It&amp;rsquo;s very valuable information you know about how it optimized the query, just know that it has to do just with those estimates and what it thought would be the most work and what actually took the longest in the query may or may not be those highest cost operators.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: Kimberly Tripp is great at driving this point home about cost being an estimate. I always think of her when this comes up.
&lt;/div&gt;
&lt;h3 id="there-is-no-magic-shortcut"&gt;There is no magic shortcut&lt;/h3&gt;
&lt;p&gt;This all means there is no single shortcut when you&amp;rsquo;re looking at a complex plan, there&amp;rsquo;s no single shortcut that just lets you know exactly where to look all the time to find the secret info.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s just not that easy and looking at big complex plans can absolutely be time-consuming. It&amp;rsquo;s not that you&amp;rsquo;re dumb it&amp;rsquo;s that it&amp;rsquo;s hard, and there is a lot to look at.&lt;/p&gt;
&lt;h3 id="collect-compiled-for-values"&gt;Collect &amp;ldquo;compiled for&amp;rdquo; values&lt;/h3&gt;
&lt;p&gt;One of the things that doesn&amp;rsquo;t always show up right in front of you in the plan that I always want to collect though is to check the properties of the plan and see what was this plan compiled for in terms of parameter values. Not all queries are parameterized, so figuring out, &amp;ldquo;okay, look at the query does it have parameters?&amp;rdquo; is part of that. If it was a parameterized query, what were the compiled for values in a cached plan.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re pulling plans out of the cache, make sure that you know what those are, and you make notes&amp;ndash; okay I&amp;rsquo;m looking at a plan that was compiled for these parameter values. One of the things that&amp;rsquo;s tricky about analyzing execution plans is: when if you rerun the query for those &amp;ldquo;compiled for&amp;rdquo; values it may be really fast. So okay, well when the query was run when it was slow, was it being executed for different parameter values?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the bad news: those aren&amp;rsquo;t in the cached plan.&lt;/p&gt;
&lt;p&gt;It may be that the query slow because if a parameter sniffing issue, where it&amp;rsquo;s compiled with certain values and then it&amp;rsquo;s slow when it runs with different values. The execution plan will give you the compiled for values, but you have to do a legwork to figure out what other values is this often executed with, and why may it have been slow. Maybe that requires doing tracing, maybe it requires looking in your application logs. There&amp;rsquo;s lots of different ways you can research this but that&amp;rsquo;s part of the piece where like all the information we need isn&amp;rsquo;t always in the plan.&lt;/p&gt;
&lt;h2 id="big-picture-interpreting-a-plan"&gt;Big picture: Interpreting a plan&lt;/h2&gt;
&lt;p&gt;When I&amp;rsquo;m interpreting a plan big picture, here&amp;rsquo;s what I do. I analyze.&lt;/p&gt;
&lt;h3 id="i-step-back"&gt;I step back&lt;/h3&gt;
&lt;p&gt;Sometimes literally zooming out to look at the plan and try to figure out, how is the data flowing through this plan?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m thinking about where I may be able to start, looking at the whole shape of the plan. Then say okay I&amp;rsquo;m gonna zoom in now on certain areas that are high cost. This is where SQL Server thought it would be the most work.&lt;/p&gt;
&lt;p&gt;Then I&amp;rsquo;m gonna step back and start asking questions about was that really the most work. I&amp;rsquo;m not gonna assume that those were the highest amount of work, I&amp;rsquo;m gonna look at those values it was compiled for and note, okay this is was optimized for these values, so if I&amp;rsquo;m executing this for different parameter values do I get different plans, and how do they compare? Maybe something I want to look at if I suspect that plan reuse is an issue.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m gonna start noting likely suspects for why I think different parts of the plan might be causing the query to be slow. Suspects include large row counts. Maybe these are large row counts from a high estimate if it&amp;rsquo;s just a cached plan. Maybe it&amp;rsquo;s just a high estimated row count, I don&amp;rsquo;t know for sure, was it right? Even if it is a lot of rows I don&amp;rsquo;t even know for sure if that was slow. It&amp;rsquo;s a possible suspect.&lt;/p&gt;
&lt;p&gt;Do I see evidence of there being spills, or do I see estimates that I think might be way off, I see anti-patterns in the query plan, where I&amp;rsquo;m like, &amp;ldquo;we&amp;rsquo;ve got a lot of functions being used here,&amp;rdquo; or &amp;ldquo;we&amp;rsquo;ve got implicit conversions that may be causing a scan,&amp;rdquo; We&amp;rsquo;ll put these in as suspects.&lt;/p&gt;
&lt;h3 id="then-i-set-up-a-repro-case-and-start-testing-things"&gt;Then I set up a repro case and start testing things&lt;/h3&gt;
&lt;p&gt;I have to check out all of these suspects, and I have to check them out even if they&amp;rsquo;re anti patterns.&lt;/p&gt;
&lt;p&gt;I have learned one lesson the hard way: when looking at execution plans to try to pinpoint what makes a query slow, this has happened to me so many times where, there&amp;rsquo;s something in the plan that&amp;rsquo;s just the glaring anti pattern. It&amp;rsquo;s a well-known thing you shouldn&amp;rsquo;t do. And you start testing things out, and that is NOT at all why the query is slow.&lt;/p&gt;
&lt;p&gt;But if you if you start harping on it too much, too early, then you really have egg on your face when you test out fixing that anti pattern and it&amp;rsquo;s still slow. Or maybe removing that anti pattern makes it even slower.&lt;/p&gt;
&lt;p&gt;Just because something is an anti pattern don&amp;rsquo;t assume that is what&amp;rsquo;s making it slow, you&amp;rsquo;ve got to test it out and check it!&lt;/p&gt;
&lt;h3 id="most-of-your-likely-suspects-are-going-to-be-innocent"&gt;Most of your &amp;rsquo;likely suspects&amp;rsquo; are going to be innocent&lt;/h3&gt;
&lt;p&gt;Execution plans and code are complicated, and you&amp;rsquo;re gonna come up with a lot of candidates that might be making the query slow, and they just don&amp;rsquo;t pan out. You&amp;rsquo;ve got to just keep hunting and figuring out, hey what is the thing that&amp;rsquo;s making this slow? If it&amp;rsquo;s part of the plan itself.&lt;/p&gt;
&lt;p&gt;Setting up that repro case and testing it is really where you start interacting with the query plan. You start testing out your hypothesis. I made this change now what happens? Does it get faster? Does it get slower?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s really where you start the query tuning process. You set up hypotheses using the plan and related info. The actual tuning process is when you dig in setting up a repro.&lt;/p&gt;
&lt;p&gt;It takes takes work, sometimes you can&amp;rsquo;t just run the query against production and sometimes you aren&amp;rsquo;t lucky enough to have a realistic development or staging database to work with. Sometimes you&amp;rsquo;ve got to set up staging data yourself outside of production so that you can test one part of a process. What if my query is slow in the middle of a nightly batch process and I&amp;rsquo;ve got to get it to the point where the data is right before that process begins in order to test the slow query? It&amp;rsquo;s absolutely worth it to do it, but yeah you have to do a little bit of work if you really want to test your hypothesis sometimes.&lt;/p&gt;
&lt;p&gt;Also, if I have a really complex query and I really want to work on part of it, I can try to break out that part of the query. Sometimes when I vastly simplify a query everything changes.&lt;/p&gt;
&lt;p&gt;I may have to do a lot of work to reproduce the behavior that I&amp;rsquo;m seeing in the problematic execution plan to be able to test it in a smaller format.&lt;/p&gt;
&lt;p&gt;Sometimes I also have to execute a query multiple times to get one execution plan in cache, and then reuse it with different parameter values.&lt;/p&gt;
&lt;p&gt;But all of these steps in setting up a repro and testing it are steps where I learn more about the nature of the execution plan how the data is really flowing through there, and why things are slow. So in this process of building the repro, I&amp;rsquo;m still working on the tuning process, I&amp;rsquo;m not wasting time.&lt;/p&gt;
&lt;h2 id="ways-to-save-time"&gt;Ways to save time&lt;/h2&gt;
&lt;p&gt;If you have a monitoring tool that looks at your SQL Server and collects information like how much CPU and how many logical and physical reads do queries use, how long do they take, and what are their cached execution plans &amp;ndash; that can be helpful because when you&amp;rsquo;re looking at a plan and you want that information of &amp;ldquo;okay, this time what parameter values was it executed with?&amp;rdquo; &amp;ldquo;How slow was it?&amp;rdquo; You have a place where you can go get those. You don&amp;rsquo;t have to setup a new trace or run a bunch of queries to figure it out.&lt;/p&gt;
&lt;p&gt;If you have SQL Server 2016 and higher the built in Query Store feature that you can enable per database collects much of this information. A lot of it is in aggregate form. It&amp;rsquo;s not as detailed, it is not a monitoring tool, but it has aggregate information that can help you figure out hey has this query had different execution plans over time? For different intervals, what were the execution statistics for that query plan in that interval? They are an aggregate, but they persist over restarts. They&amp;rsquo;re a lot more stable than just hoping the information you want is in memory, and that can be really helpful. It&amp;rsquo;s built right into the SQL Server.&lt;/p&gt;
&lt;h2 id="there-is-an-art-to-pulling-this-all-together"&gt;There is an art to pulling this all together&lt;/h2&gt;
&lt;p&gt;Which parts of the plan are taking the longest, what should you do to change the behavior? Right? Because even in an execution plan, even when I&amp;rsquo;ve analyzed, here here&amp;rsquo;s the part of it that&amp;rsquo;s slow, I then have to start making additional guesses about, okay well here&amp;rsquo;s the part that&amp;rsquo;s slow what do I do to make it faster?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve absolutely found it to be the case where I do a lot of work I figure out exactly which part of the complex plan is slow and then I stop and I&amp;rsquo;m like uh-oh, geez, how do I fix it???&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s no obvious option, and I&amp;rsquo;ve got to be a little creative with saying, &amp;ldquo;okay, do I need to rewrite the query? Do I need to create an index? Do I need to change an index? Do I need to use a hint?&amp;rdquo; What are the things I can do to influence SQL Server&amp;rsquo;s behavior? Then test them.&lt;/p&gt;
&lt;p&gt;Very often the thing I want to do to change the behavior may make the query slower, so I have to make sure that my change will reliably make the query faster, even when it&amp;rsquo;s optimized for different parameter values. Narrowing as you go through this process&amp;ndash; narrowing down which parts of this query are making it slower&amp;ndash; you&amp;rsquo;ll learn more about the query and you&amp;rsquo;re really not wasting time.&lt;/p&gt;
&lt;p&gt;The more you learn about the query, you&amp;rsquo;re gonna use that information when you have to start guessing about how to make it faster as well, and trying to make it faster reliably.&lt;/p&gt;
&lt;p&gt;The more that you break down execution plans and dive in &amp;ndash; it can be frustrating and you&amp;rsquo;re not gonna have a success every time, trust me I have not had success every time. I&amp;rsquo;ve looked at an execution plan, I need to figure out more information, I need to set up a repro, I need to get an actual plan, it will take work to do that.&lt;/p&gt;
&lt;h2 id="the-more-you-do-this-the-faster-you-become"&gt;The more you do this, the faster you become&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll develop those suspects more quickly and you&amp;rsquo;ll come up with different tests you can do to see if you can make it faster more quickly as well. I think it really becomes more fun the more you do it, too.&lt;/p&gt;
&lt;p&gt;Thanks for joining me for Dear SQL DBA. I&amp;rsquo;m Kendra Little from LittleKendra.com&lt;/p&gt;</description></item><item><title>The Case of the Rowgroup Deadlock in a Columnstore Index</title><link>https://kendralittle.com/2017/09/21/the-case-of-the-rowgroup-deadlock-in-a-columnstore-index/</link><pubDate>Thu, 21 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/21/the-case-of-the-rowgroup-deadlock-in-a-columnstore-index/</guid><description>&lt;p&gt;I came across a fun deadlock when writing demos for my session on the Read Committed isolation level this week. (It&amp;rsquo;s OK to call it &amp;ldquo;fun&amp;rdquo; when it&amp;rsquo;s not production code, right?)&lt;/p&gt;
&lt;p&gt;I was playing around with a nonclustered columnstore index on a disk-based table. Here&amp;rsquo;s what I was doing:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session 1:&lt;/strong&gt; this session repeatedly changed the value for a single row, back and forth. This puts it into the delta store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session 2:&lt;/strong&gt; this session repeatedly counted the number of rows in the table, using the columnstore index.&lt;/p&gt;
&lt;p&gt;With my sample data in this scenario, I found I frequently generated deadlocks.&lt;/p&gt;
&lt;h2 id="lets-look-at-the-deadlock-graph"&gt;Let&amp;rsquo;s look at the deadlock graph&lt;/h2&gt;
&lt;p&gt;I started up an Extended Events trace for the xml_deadlock_report event, and here&amp;rsquo;s what this deadlock looks like (with some annotations)&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/deadlock-graph-rowgroup-1024x221.png"&gt;
&lt;/figure&gt;
&lt;h2 id="breaking-it-down"&gt;Breaking it down&lt;/h2&gt;
&lt;p&gt;The circle on the left is Session 2 - it was running a SELECT COUNT that used the nonclustered columnstore index. It was chosen as the deadlock victim.&lt;/p&gt;
&lt;p&gt;Reading the arrows, the SELECT COUNT query:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Had a lock on the compressed rowgroup in the columnstore index&lt;/li&gt;
&lt;li&gt;Wanted a shared lock on the b-tree delta store for the columnstore index to count the rows for data that had been changed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The circle on the right is Session 1 - it was running an update that changed the value for one column in one row. Reading the arrows, the UPDATE query:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Had an intent exclusive lock on the b-tree delta store&lt;/li&gt;
&lt;li&gt;Wanted an intent exclusive lock on the compressed rowgroup (presumably to do the work to make sure it was clear the related row is in the delta store)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voila&amp;ndash; deadlock!&lt;/p&gt;
&lt;h2 id="how-do-i-fix-it"&gt;How do I fix it?&lt;/h2&gt;
&lt;p&gt;If I really want to churn changes into my columnstore index at the same time that I rapid-fire query the data, I may want to change my isolation level for the query counting the data.&lt;/p&gt;
&lt;p&gt;Read committed snapshot isolation or snapshot isolation for the SELECT COUNT query  can change this blocking scenario and sneak us right past those deadlocks &amp;ndash; as long as enabling those is the right thing for my application and my database server.&lt;/p&gt;
&lt;h2 id="the-more-clever-we-get-the-more-ways-things-can-backfire"&gt;The more clever we get, the more ways things can backfire&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not writing this post to bash columnstore indexes &amp;ndash; far from it. Churning tons of updates into a columnstore index isn&amp;rsquo;t necessarily what you want to do.&lt;/p&gt;
&lt;p&gt;Changing to indexes or data can cause deadlocks. It can also make them go away! That&amp;rsquo;s a fact of life, and as we add more indexing tools to our toolkits, we still gotta live with it.&lt;/p&gt;
&lt;h2 id="want-to-learn-more-about-deadlocks"&gt;Want to learn more about deadlocks?&lt;/h2&gt;
&lt;p&gt;Check out my free course, &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;Troubleshooting Blocking &amp;amp; Deadlocks for Beginners&lt;/a&gt;. It gives you example code to create a deadlock, and walks you through tracing and decoding the deadlock graph, too.&lt;/p&gt;</description></item><item><title>Do I Need to Master PowerShell?</title><link>https://kendralittle.com/2017/09/12/do-i-need-to-master-powershell/</link><pubDate>Tue, 12 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/12/do-i-need-to-master-powershell/</guid><description>&lt;p&gt;As a SQL Server DBA, do you need to be a master of PowerShell scripts?&lt;/p&gt;
&lt;p&gt;In this 9 minute episode, I talk about how much you need to know about PowerShell, and examples of ways I personally use (and struggle with) PowerShell.&lt;/p&gt;
&lt;p&gt;This episode is part of &lt;a href="http://tsqltuesday.com/"&gt;TSQLTuesday&lt;/a&gt;. This month, &lt;a href="https://sqldbawithabeard.com/2017/09/05/tsql2sday-94-lets-get-all-posh/"&gt;our topic is hosted by Rob Sewell&lt;/a&gt;. Thanks, Rob!&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now or read the transcript below? Listen in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/uJmqe4PVqXU?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="related-links"&gt;Related links&lt;/h2&gt;
&lt;p&gt;PowerShell fans love to join the SQL Server Slack channel. &lt;a href="https://dbatools.io/slack/"&gt;You can join here!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I mention Adam Machanic&amp;rsquo;s SQLQueryStress in this episode. The code is &lt;a href="https://github.com/ErikEJ/SqlQueryStress"&gt;now on GitHub&lt;/a&gt;, is managed by Erik Ejlskov Jensen, and is open for contributions.&lt;/p&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;Welcome to Dear SQL DBA: a podcast and YouTube show for SQL Server developers and database administrators. I&amp;rsquo;m Kendra Little.&lt;/p&gt;
&lt;p&gt;This week&amp;rsquo;s episode is about PowerShell, and this episode is inspired both by a reader&amp;rsquo;s question, and by TSQLTuesday. It&amp;rsquo;s TSQLTuesday for September 2017, and the host this month is Rob Sewell. Rob has challenged people to think about, talk about, and to code a little bit with PowerShell this month.&lt;/p&gt;
&lt;p&gt;I also recently got a question from a reader who asked: &amp;ldquo;As a database administrator, do I need to master PowerShell? How important is it for me to become an expert on PowerShell?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This is something that a lot of people wonder&amp;hellip;&lt;/p&gt;
&lt;h3 id="how-great-do-i-need-to-be-at-scripting-as-a-database-administrator"&gt;How great do I need to be at scripting as a database administrator?&lt;/h3&gt;
&lt;p&gt;The amount of PowerShell that you need to know varies, but I do think that these days PowerShell really is a little bit of a default when it comes to basic things like managing files and directories and Windows.&lt;/p&gt;
&lt;h4 id="junior-dbas"&gt;Junior DBAs&lt;/h4&gt;
&lt;p&gt;Even junior DBAs need to be comfortable with different methods of managing files and folders, because of things like making copies of backups and moving backup files around &amp;ndash; managing directories and permissions.&lt;/p&gt;
&lt;p&gt;PowerShell is a great tool. When when I first started as a DBA, we just had Ye Olde Command Prompt, and we did DOS scripting for a lot of things. I think the default now is really to use PowerShell.&lt;/p&gt;
&lt;p&gt;Getting comfortable with those basics isn&amp;rsquo;t super hard. You&amp;rsquo;ve got to be comfortable looking at simple PowerShell scripts as a Junior DBA.&lt;/p&gt;
&lt;h4 id="senior-dbas"&gt;Senior DBAs&lt;/h4&gt;
&lt;p&gt;As you advance in your career, you do want to build some more skills there but a lot of it&amp;ndash; even as a Senior DBA you don&amp;rsquo;t really need to master PowerShell, as much as you just need to be comfortable searching for scripts, reviewing them, adapting and testing them out safely, and then fitting them to your own purposes.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t have to write a bunch of code from scratch. You don&amp;rsquo;t have to be necessarily super fluent. You can instead be pretty good at finding good sources, cobbling together code.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s lots of folks out there in communities now who you can ask: do you have a snippet of code that I could use to do something? Could you review my PowerShell script for this and let me know if there&amp;rsquo;s a better way to do this?&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s the SQL Server Slack community, there&amp;rsquo;s lots of PowerShell fans in there. There&amp;rsquo;s PowerShell folks on Twitter that you can ask for tips on things. You don&amp;rsquo;t have to be great at PowerShell yourself.&lt;/p&gt;
&lt;h4 id="what-if-you-love-powershell"&gt;What if you LOVE PowerShell?&lt;/h4&gt;
&lt;p&gt;If you do really like PowerShell, if you start playing with it, and you find that you love scripting in it, and you want to do a lot of it, you can find DBA jobs where you can write a lot of PowerShell and use it to automate installations.&lt;/p&gt;
&lt;p&gt;Set up very large environments. Do really cool things in the cloud. Do really cool migrations.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re into the PowerShell and you find you have a talent for it, you really want to master it, then by all means that can fit really well into a career of working with data!&lt;/p&gt;
&lt;p&gt;It just isn&amp;rsquo;t necessarily &lt;em&gt;required&lt;/em&gt;: there are a lot of jobs that don&amp;rsquo;t require writing PowerShell all the time and expanding your knowledge. But dabbling in it is super helpful for many of us.&lt;/p&gt;
&lt;h3 id="i-have-been-messing-with-powershell-for-a-while"&gt;I have been messing with PowerShell for a while&lt;/h3&gt;
&lt;p&gt;Back when I was a DBA, I loved automating SQL Server installations. It was fairly early days for PowerShell then, but I did use it as part of the set up scripts for our environment. We had enough SQL Servers that installing and configuring Windows, and installing and configuring SQL Server &amp;ndash;sometimes in clusters sometimes not &amp;ndash; it was something we did fairly commonly. Scripting as much as I could and using PowerShell in there was fun, and it was really handy.&lt;/p&gt;
&lt;p&gt;These days you can do more and more with PowerShell. I had to call out to a lot of more old-fashioned tools to do things like configure the local security policy, and I imagine (I haven&amp;rsquo;t looked at this lately) that there&amp;rsquo;s better ways to do that in PowerShell these days. It&amp;rsquo;s been quite a few years since I did that project!&lt;/p&gt;
&lt;p&gt;These days I still use PowerShell. I have been using it recently to generate test load against SQL Server. I wrote a session on finding top queries in SQL Server, and to do a demo of finding top queries you need to generate some activity with queries, right?&lt;/p&gt;
&lt;p&gt;One of the cool things about using PowerShell for this &amp;ndash; you might just wonder, &amp;ldquo;why don&amp;rsquo;t you just write a script that you run in Management Studio to generate the activity?&amp;rdquo; You can do that, but with PowerShell it acts more like a an application. Management Studio is an application, I get that, but for example with PowerShell, when you&amp;rsquo;re calling a stored procedure in SQL Server you can say, &amp;ldquo;hey I&amp;rsquo;m calling a stored procedure&amp;rdquo; and be really clear about the fact that you&amp;rsquo;re not executing ad-hoc SQL. That actually shows up differently in the performance counters in the SQL Server, because the SQL server sees the command and knows immediately, &amp;ldquo;hey this is a stored procedure! I&amp;rsquo;m going to go match it.&amp;rdquo; instead of saying, &amp;ldquo;oh, this is query text. I see in the query text it&amp;rsquo;s the stored procedure, I&amp;rsquo;m gonna go run it.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;You can also easily measure duration in the PowerShell.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really easy to do things like set up reusable code and functions, to say, &amp;ldquo;okay, we&amp;rsquo;re going to loop through and run this a certain amount of times.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="there-are-some-things-though-that-i-struggle-with-with-powershell"&gt;There are some things though that I struggle with with PowerShell&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s really easy to do things like &amp;ndash; PowerShell has &amp;ldquo;start-job&amp;rdquo;, where you can say, &amp;ldquo;okay I want to start a few jobs.&amp;rdquo; This sounds like a great way to be able to run activity on multiple threads at once against your SQL Server. And it works, but the thing I&amp;rsquo;ve struggled with is it&amp;rsquo;s not that easy to control and make all the jobs start at the same time.&lt;/p&gt;
&lt;p&gt;For lots of demo purposes, I want multiple threads running something at the same time to be able to generate activity in some patterns, and what I&amp;rsquo;d find with start-job is some of my jobs start, and then some of the other jobs start a little later. Which when it comes to things like automation is probably what you want! You probably don&amp;rsquo;t necessarily want all these jobs hammering your laptop or wherever you&amp;rsquo;re running the jobs from at the same time.&lt;/p&gt;
&lt;p&gt;But for my purposes it wasn&amp;rsquo;t that perfect, and it wasn&amp;rsquo;t that easy to control.&lt;/p&gt;
&lt;p&gt;That being said, if I want to run a burst of queries on multiple threads exactly at the same time, I might use another tool for that. There&amp;rsquo;s a tool called SQLQueryStress which was originally written by Adam Machanic instead of PowerShell. If you search for it, I think someone else has taken over. I think Adam open-sourced it, and someone else has taken control of the code, but for testing and generating demos, there&amp;rsquo;s other options too.&lt;/p&gt;
&lt;h3 id="powershell-is-really-flexible-and-i-love-having-multiple-tools-out-there"&gt;PowerShell is really flexible, and I love having multiple tools out there!&lt;/h3&gt;
&lt;p&gt;I also suspect that maybe someday someone will listen to this episode and say, &amp;ldquo;I&amp;rsquo;ve got a great way that you can make running those jobs easier, or a different way to do it.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Because the cool thing about PowerShell is it&amp;rsquo;s really flexible and &lt;em&gt;a lot&lt;/em&gt; of people love using it. It&amp;rsquo;s always evolving, there&amp;rsquo;s new cool stuff to do.&lt;/p&gt;
&lt;p&gt;Whether you are just getting comfortable with it, whether you&amp;rsquo;re at the level where you&amp;rsquo;re finding and testing scripts from other people, or if you are that person who loves to write scripts, I encourage you to share your scripts online and to join the SQL Server community&amp;ndash; whether it&amp;rsquo;s in the SQL Server Slack Channel, or on Twitter, and chat about PowerShell.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href="http://tsqltuesday.com/"&gt;TSQLTuesday.com&lt;/a&gt; if you want to read all of the posts that people put up for SQL Tuesday on PowerShell. Or maybe you want to join us and participate in TSQLTuesday yourself in a future month?&lt;/p&gt;</description></item><item><title>SSMS Shortcuts &amp; Secrets - Live Webcast Edition (video)</title><link>https://kendralittle.com/2017/09/11/ssms-shortcuts-secrets-live-webcast-edition-video/</link><pubDate>Mon, 11 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/11/ssms-shortcuts-secrets-live-webcast-edition-video/</guid><description>&lt;p&gt;Last week, I had a great time giving a webcast for the terrific &lt;a href="http://fundamentals.pass.org/"&gt;DBA Fundamentals Virtual Chapter&lt;/a&gt;. If you like free online training, check them out and sign up for future events.&lt;/p&gt;
&lt;p&gt;Steve and Shane were kind enough to record and share the video of the live session. This video covers shortcuts to manage and switch between sessions, tips and shortcuts for managing Intellisense, and a few stupid pet tricks.&lt;/p&gt;
&lt;p&gt;We had lots of fun, and I was delighted to get suggestions from the audience for their favorite keyboard shortcuts to open Object Explorer, and to dock windows. (Thanks Claudio and Michael!)&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/gIPfz9cyGiI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="want-to-grab-the-cheat-sheet-and-the-wallpaper"&gt;Want to grab the cheat sheet and the wallpaper?&lt;/h2&gt;
&lt;p&gt;Get that, plus more SSMS Shortcuts and Secrets, in &lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;my free online course&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And don&amp;rsquo;t worry: as we get more enhancements and awesome changes in SSMS, I&amp;rsquo;ll keep the course and cheat sheet updated.&lt;/p&gt;</description></item><item><title>SQL PASS Summit 2017: Tips on Attending</title><link>https://kendralittle.com/2017/09/07/sql-pass-summit-2017-why-im-excited-and-tips-on-attending/</link><pubDate>Thu, 07 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/07/sql-pass-summit-2017-why-im-excited-and-tips-on-attending/</guid><description>&lt;p&gt;I&amp;rsquo;ll be attending and presenting at the SQL PASS Summit in Seattle Washington this year from Oct 31-Nov 3. In this week&amp;rsquo;s 19 minute episode, I share why I&amp;rsquo;m excited about going and why I&amp;rsquo;ve purchased a seat for a pre-conference session. I also give my tips on how to get the most value out of a big conference like the PASS Summit.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/g6E8DNKN4UM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;Welcome to &amp;lsquo;Dear SQL DBA&amp;rsquo;, a podcast and YouTube show for SQL Server Database Administrators and developers. I&amp;rsquo;m Kendra little from LittleKendra.com.&lt;/p&gt;
&lt;p&gt;In today&amp;rsquo;s episode I&amp;rsquo;m talking about the SQL PASS Summit this year in 2017, why I&amp;rsquo;m really excited to attend, and also some tips on getting the most out of attending the PASS Summit (if you are lucky enough to attend also).&lt;/p&gt;
&lt;h3 id="i-will-be-speaking-at-the-summit-this-year"&gt;I will be speaking at the Summit this year!&lt;/h3&gt;
&lt;p&gt;I have a regular session. It&amp;rsquo;s going to be 70 minutes, and it&amp;rsquo;s called, &amp;ldquo;Why did my clever index change backfire?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The session is going to be a ton of fun, because I get to show different cases where you design an index change that in theory is going to make performance better, but in actuality something goes terribly wrong. Either performance gets lower, or something bad happens. I&amp;rsquo;ll talk about all those pitfalls and how to avoid them: because indexes are really powerful tools so that you can use to massively increase your performance, you&amp;rsquo;ve just got to know what to look out for! Because there are so many ways to screw things up&amp;hellip; as I continually find more and more in my life as time goes on.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m not just excited about attending because I&amp;rsquo;m speaking. That&amp;rsquo;s only part of it.&lt;/p&gt;
&lt;h3 id="i-am-really-excited-about-attending-a-pre-conference-session"&gt;I am really excited about attending a pre-conference session&lt;/h3&gt;
&lt;p&gt;If you get to go to the PASS Summit, I very much encourage you to try to find a way to attend at least one pre-conference session. There&amp;rsquo;s actually two days of pre cons.&lt;/p&gt;
&lt;p&gt;They cost extra money from the Summit itself, but they are a huge value and they really add to your whole experience, because you get to go in-depth and spend a whole day thinking about a topic with a great speaker. You&amp;rsquo;ve the chance to meet other people who are attending the session; talk to them during lunch; figure out&amp;quot; are they trying to solve the same problems you are? It&amp;rsquo;s also a great way to start off the Summit by focusing on something in depth, and can often give you ideas about other sessions you want to see during the Summit, give you a start on working on some problems.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a great value and a really great way to start the conference.&lt;/p&gt;
&lt;h3 id="i-first-heard-about-the-pass-summit-years-ago-from-database-administrators-i-was-working-with-at-a-dot-com"&gt;I first heard about the PASS Summit years ago from database administrators I was working with at a dot com&lt;/h3&gt;
&lt;p&gt;I didn&amp;rsquo;t yet have a DBA job. I wanted to be a DBA, but I hadn&amp;rsquo;t landed an official DBA job! I just got to work with SQL Server a little bit, but of course I would hang out with the DBAs. I thought they were awesome! They&amp;rsquo;re really fun people and just fascinating &amp;ndash; and I&amp;rsquo;m still friends with many of those folks to this day. They really ARE fun people. They got to go to the PASS Summit (a lot of their team did), and it was in Denver the year I&amp;rsquo;m thinking of.&lt;/p&gt;
&lt;p&gt;I was like, &amp;ldquo;so what&amp;rsquo;s this all about?&amp;rdquo; They said it&amp;rsquo;s this event where you can learn about new features in SQL Server; how to do things better in SQL Server. And there&amp;rsquo;s SQL Server developers and database administrators from around the world. There&amp;rsquo;s people from Microsoft, there&amp;rsquo;s community speakers, and they said that if you were interested in learning about SQL Server, it&amp;rsquo;s just non-stop learning and SQL Server nerdery, throughout the duration of the conference.&lt;/p&gt;
&lt;h3 id="what-id-do-differently-if-i-was-attending-for-the-first-time-again"&gt;What I&amp;rsquo;d do differently if I was attending for the first time again&lt;/h3&gt;
&lt;p&gt;I finally got to attend a few years later. I was very excited the first time I attended, but I was super shy. I didn&amp;rsquo;t know how to talk to strangers at all, and I attended sessions and I learned a ton but I didn&amp;rsquo;t make it to a pre-con.&lt;/p&gt;
&lt;p&gt;I think if I had actually figured out what pre-con I wanted to attend, and had been able to make a case for why it would help me &amp;ndash; I think I probably could have gotten it approved. I just didn&amp;rsquo;t know how helpful it would be. I didn&amp;rsquo;t know to ask for it.&lt;/p&gt;
&lt;p&gt;I went to lots of sessions, and I made tons of notes but I didn&amp;rsquo;t really make any connections with new people. I&amp;rsquo;m super glad I went, but my one regret &amp;ndash; if I had to go back and do it again &amp;ndash; I would get out of my shell more.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a bunch of ways you can do this, even if you tend to be a little bit shy like me. When it comes to face-to-face interactions, if I don&amp;rsquo;t know someone yet I am often at a loss for words. I&amp;rsquo;m not sure how to break the glass.&lt;/p&gt;
&lt;h2 id="breaking-out-of-your-shell-first-timer-events"&gt;Breaking out of your shell: first timer events&lt;/h2&gt;
&lt;p&gt;Well, there are events for first-timers! They change them up on different years, but usually there are some events specifically for folks who are attending the Summit for the first time, where you can go and learn about the Summit: learn about different opportunities.&lt;/p&gt;
&lt;p&gt;For example, there&amp;rsquo;s a lunch one day that&amp;rsquo;s called the &amp;ldquo;Birds of a Feather&amp;rdquo; lunch, where in the cafeteria there are different tables, and you can sit at a table for people who are interested in maybe Reporting Services, or Power BI, or whatever you&amp;rsquo;re interested in. You can meet people who work with the same tools you do, and chat with them.&lt;/p&gt;
&lt;p&gt;The first timers events will help familiarize you with all these different opportunities so that you can figure out, &amp;ldquo;On this day I actually do want to eat lunch in the cafeteria. Maybe on another day I want to go try out a Seattle place that serves great Vietnamese pho, but on certain days maybe I do want to have lunch (at the convention center).&amp;rdquo; So hit up the first-timers event.&lt;/p&gt;
&lt;p&gt;A secret: even if you aren&amp;rsquo;t a first-timer&amp;hellip; maybe this is your second time attending but you never attended the first-timer event.. I think you&amp;rsquo;re probably fine going, right? I wouldn&amp;rsquo;t worry too much if it&amp;rsquo;s not your official first time status. It&amp;rsquo;s all about helping you get the most out of the event.&lt;/p&gt;
&lt;h3 id="there-are-also-lots-of-evening-networking-events"&gt;There are also lots of evening networking events&lt;/h3&gt;
&lt;p&gt;Last year somebody put together for the first time a game night event! I didn&amp;rsquo;t get to go because it was the same night that my local user group was having a get-together at the conference. We actually got together and talked about what different people had liked so far, what we were planning on seeing &amp;ndash;it&amp;rsquo;s really fun to get in touch sometimes with your local user group people there, too&amp;ndash; but look for things that are open, that you might be interested in joining.&lt;/p&gt;
&lt;p&gt;Maybe it&amp;rsquo;s a game night, maybe it&amp;rsquo;s a party, look for the ones that might be useful for you.&lt;/p&gt;
&lt;h3 id="get-set-up-on-twitter-before-the-event-even-if-you-dont-tweet"&gt;Get set up on Twitter before the event, even if you don&amp;rsquo;t tweet.&lt;/h3&gt;
&lt;p&gt;Lots of people at the Summit like to tweet and they&amp;rsquo;ll use a hashtag&amp;ndash; I don&amp;rsquo;t know exactly what the official hashtag is going to be this year, it may be #summit17, it may be something else&amp;ndash; get set up on Twitter a couple weeks before the event and see what folks are using as the hashtag, because that hashtag will be really useful to be able to read on your phone.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Oh there&amp;rsquo;s a giveaway down in the vendor area!&amp;rdquo; maybe that you&amp;rsquo;re interested in. Or &amp;ldquo;oh the book signing is going on,&amp;rdquo; or &amp;ldquo;there&amp;rsquo;s something cool in the Community Zone,&amp;rdquo; You can use that to find out about things even if you don&amp;rsquo;t plan to actively tweet.&lt;/p&gt;
&lt;p&gt;One lesson that it took me a little while to learn (and that I still have to work on a little bit) is that&amp;hellip;&lt;/p&gt;
&lt;h3 id="you-shouldnt-feel-guilty-if-you-dont-want-to-stay-out-late"&gt;You shouldn&amp;rsquo;t feel guilty if you don&amp;rsquo;t want to stay out late&lt;/h3&gt;
&lt;p&gt;I am one of those folks who loves going out to dinner with folks, I love networking events in the early evening, but I&amp;rsquo;ve always been kind of an old person at heart. I don&amp;rsquo;t like to stay out till 2:00 a.m. If I stay out till 2:00 a.m. I won&amp;rsquo;t want to get up and learn at 8:00 in the morning. I&amp;rsquo;ll want to sleep till noon.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re the kind of person who needs your eight hours (or eight and a half hours) of sleep, don&amp;rsquo;t feel bad about it! Some people like to go out, they like to drink, they like to socialize. For those of us who really enjoy sound sleep and need it to stay sane, we gotta take care of ourselves. Don&amp;rsquo;t feel like you have to actually do all the nightlife, you really can get tons of interaction out of the daytime events.&lt;/p&gt;
&lt;h3 id="that-being-said-leave-your-work-behind"&gt;That being said, leave your work behind&lt;/h3&gt;
&lt;p&gt;Before you attend the conference make a plan for other folks to handle things, and try to let them do it! It can be tempting to VPN back in during the day and work on stuff and take care of it, because you&amp;rsquo;re better at it.&lt;/p&gt;
&lt;p&gt;Maybe you are better at it, but a couple of things:&lt;/p&gt;
&lt;p&gt;You aren&amp;rsquo;t really paying attention to the session when you&amp;rsquo;re VPN&amp;rsquo;d into work. You are not! Your brain should be paying attention to the environment you&amp;rsquo;re working on. You&amp;rsquo;re only half listening, and you&amp;rsquo;re really not focusing. You&amp;rsquo;re not learning.&lt;/p&gt;
&lt;p&gt;Also, if you can&amp;rsquo;t let go of the keyboard at work, what happens if you win the lottery someday? I mean, they need to be able to be self-sufficient, even if they aren&amp;rsquo;t as fast as you, even if you&amp;rsquo;re better at certain things. You need to disconnect and let the people at the office take care of the office.&lt;/p&gt;
&lt;p&gt;So prep for that, and do the documentation you need ahead of time. Make sure you have a backup. But be prepared to be someone else&amp;rsquo;s backup when they&amp;rsquo;re away too!&lt;/p&gt;
&lt;p&gt;Really your job at the Summit is to learn and to think about strategies for solving problems at work. Leave behind the actual LIVE work, but&amp;hellip;&lt;/p&gt;
&lt;h3 id="bring-along-the-top-three-problems-that-you-want-to-research-strategize-or-solve-at-the-summit"&gt;Bring along the top three problems that you want to research, strategize, or solve at the Summit&lt;/h3&gt;
&lt;p&gt;What are the things that you really need to get better at? Write them down, and keep track of them during the Summit because you want to make sure that you&amp;rsquo;re learning things around those big areas that are relevant.&lt;/p&gt;
&lt;p&gt;Maybe they&amp;rsquo;re big picture items, maybe they&amp;rsquo;re really specific, but pick three things that you really want to work on that help the problems back at the office and work on those. Don&amp;rsquo;t work on break-fix things or individual tickets or individual changes while you&amp;rsquo;re at the Summit. You&amp;rsquo;re just wasting time and money by doing that.&lt;/p&gt;
&lt;h3 id="you-also-want-to-buy-the-recordings"&gt;You also want to buy the recordings&lt;/h3&gt;
&lt;p&gt;Now, I realize that again this can cost extra money. I believe these usually are an extra cost, but the recordings usually are not very expensive at the Summit. (I don&amp;rsquo;t know exactly what the published price is this year.)&lt;/p&gt;
&lt;p&gt;The recordings are typically just for the regular sessions. In other words you&amp;rsquo;re not going to get all the pre conferences with the recordings, but by buying the recordings for the regular sessions, this means that if you see a really great session, you have the ability to watch it again later. Hugely valuable.&lt;/p&gt;
&lt;p&gt;Also, if you see a really great session and maybe you get into an interesting conversation with the people you&amp;rsquo;re sitting near, or maybe you go up to the front of the room and you ask the speaker a question after the session, and you get into either a conversation with them or other people who were in line &amp;ndash; if you&amp;rsquo;ve bought the session recordings, you now have the ability to use the &amp;ldquo;Hallway Track&amp;rdquo; at the Summit.&lt;/p&gt;
&lt;p&gt;You can continue that conversation in the Community Zone even if another session you want to attend is going on. You know, &amp;ldquo;OK, I can catch that later on the recordings, because I can learn from this interaction live here that I can&amp;rsquo;t have later.&amp;rdquo; You can also use things like &amp;ndash; Microsoft often has a clinic area where you can go and ask your questions of really smart people who work for Microsoft, and learn from them.&lt;/p&gt;
&lt;p&gt;Maybe you need to do some of that work during a time that makes you miss a session, or maybe you get into a great conversation in the vendor expo hall, and you learn how to really do something cool with a monitoring tool you already have. Buying the session recordings mean that you can do all these things without constantly scrambling to get into a session, and then you&amp;rsquo;re late and all the seats are full and all of that. You can chill out a little bit knowing that you can watch things later.&lt;/p&gt;
&lt;p&gt;Another tip I have if you&amp;rsquo;re going and you&amp;rsquo;re lucky enough to have other co-workers who go with you as well: that can be great, but&amp;hellip;&lt;/p&gt;
&lt;h3 id="divide-and-conquer"&gt;Divide and conquer&lt;/h3&gt;
&lt;p&gt;Split up and say, &amp;ldquo;okay, if we&amp;rsquo;re interested in the same topics, we&amp;rsquo;ll split up.&amp;rdquo; Oftentimes we have this problem where there&amp;rsquo;s so much good content at the Summit they have so many tracks that there can be really good things all on at the same time. It&amp;rsquo;s hard to be in two places at once! Now you you want to buy the recordings but it&amp;rsquo;s also great to be able to ask questions and be in the room. So split up when you&amp;rsquo;re there with a coworker, and say, &amp;ldquo;OK, you go to this one, and I&amp;rsquo;ll go to this other session. We&amp;rsquo;ll each make notes and we&amp;rsquo;ll compare notes afterwards.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another reason to split up though. What I have found is if I am at an event like the PASS Summit with close co-workers, I am a lot less likely to talk to other attendees. Because it&amp;rsquo;s just human nature to have this real tendency to&amp;ndash; you know each other, you&amp;rsquo;re sitting together you&amp;rsquo;re chatting together, and you just don&amp;rsquo;t reach out to people as naturally. You&amp;rsquo;re much less likely to say to the person sitting next to you, &amp;ldquo;hey where are you from? What kind of work do you do?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Because you&amp;rsquo;re there with your coworker. You and your coworker can network back at the office though! It&amp;rsquo;s better for you to meet other people and to find out, &amp;ldquo;Hey, what is your experience working with columnstore indexes? Have you tried it in production yet? How is it working for you?&amp;rdquo; Right? Because you can get that experience from your co-workers at other times. It&amp;rsquo;s these community members who also have experience that you want to get it from. So splitting up, dividing and conquering, and making that effort to talk to new people is absolutely worth it.&lt;/p&gt;
&lt;h3 id="im-a-huge-believer-in-making-notes"&gt;I&amp;rsquo;m a huge believer in making notes&lt;/h3&gt;
&lt;p&gt;I like to write things down with pen and paper and then transcribe them. Maybe you like to type. Either way, that&amp;rsquo;s fine but making notes while you&amp;rsquo;re at the conference each day is really valuable. I like to share those notes with coworkers. Every time I went to the PASS Summit, I would take notes on what I learned, and especially ideas that came up with if we might be able to apply that in X area. And then when I got back to the office, I would share those notes with my teammates and say, &amp;ldquo;hey if you want to read these, here&amp;rsquo;s the location they&amp;rsquo;re in. If you want to talk about any of these ideas then check them out as well.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Now you do need to be careful: it&amp;rsquo;s not always cool to just take the slide deck and share those with everybody. Pay attention to the rules of the conference.&lt;/p&gt;
&lt;p&gt;Sharing your notes is usually fine but sharing other people&amp;rsquo;s copyrighted materials is different. I&amp;rsquo;m really talking about notes that you&amp;rsquo;re making and ideas that you&amp;rsquo;re having about implementing things in your workplace. Sharing what you&amp;rsquo;ve learned is usually fine, sharing other people&amp;rsquo;s copyrighted materials not so much.&lt;/p&gt;
&lt;h3 id="take-business-cards-with-you"&gt;Take business cards with you&lt;/h3&gt;
&lt;p&gt;DBAs and developers, we are not always the kind of people who like to have business cards. You can be creative&amp;ndash; maybe you want to get stickers made.&lt;/p&gt;
&lt;p&gt;I love Sticker Mule, it&amp;rsquo;s a company that you can buy custom stickers from. Maybe you want to make a sticker instead of a business card that has your email address on it and your job title or whatever you want. You could do that, get creative. You can make really rudimentary business cards if you want to.&lt;/p&gt;
&lt;p&gt;If you want to just photocopy something and cut it into squares, what you really want is the ability to trade contact info with people you meet at the conference, so that maybe later you want to say, &amp;ldquo;hey I would love to get in touch with you, and if I have questions about writing a PowerShell script that&amp;rsquo;s similar to what you&amp;rsquo;re talking about, would it be okay if I emailed you or tweet to you?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;You just want to have something to trade to keep in touch with the people you meet later, so some sort of business card or sticker is great to be able to have at the PASS Summit. there&amp;rsquo;s so many folks that having that exchange can really help you later on to remember people who you&amp;rsquo;d like to get in touch with.&lt;/p&gt;
&lt;h3 id="i-have-a-coupon-code-if-you-are-registering-for-the-summit"&gt;I have a coupon code if you are registering for the Summit!&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re finally getting there and you&amp;rsquo;re able to go, my coupon code is &lt;strong&gt;BL150GK&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That will save you a hundred and fifty bucks on registration. &lt;a href="http://www.pass.org/summit/2017/RegisterNow.aspx"&gt;Go to pass.org/Summit and learn all about Summit 2017&lt;/a&gt;. If you&amp;rsquo;re lucky enough to get to attend this year, I hope to see you there! there&amp;rsquo;s gonna be a lot of people it&amp;rsquo;s gonna be great so hopefully we cross paths and if you don&amp;rsquo;t get to make it this year then maybe we will see one another at another conference someday down the line.&lt;/p&gt;
&lt;p&gt;Thanks for joining me for this episode of Dear SQL DBA. I&amp;rsquo;m Kendra Little and I&amp;rsquo;ll see you again next week.&lt;/p&gt;</description></item><item><title>Shortcut Update: Toggling Intellisense in SSMS</title><link>https://kendralittle.com/2017/09/06/shortcut-update-toggling-intellisense-in-ssms/</link><pubDate>Wed, 06 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/06/shortcut-update-toggling-intellisense-in-ssms/</guid><description>&lt;p&gt;I like to use the keyboard whenever I can in SQL Server Management Studio. It&amp;rsquo;s not always easy to remember every shortcut though&amp;ndash; especially when those shortcuts change!&lt;/p&gt;
&lt;p&gt;Since around the SQL Server 2012 era, you&amp;rsquo;ve been able to switch Intellisense on or  off on SSMS with the shortcut chord: CTRL + Q, CTRL + I. I remembered this as &amp;ldquo;Control Quacky Intellisense.&amp;rdquo;&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tuxedo-cat-monacle2-e1504559631111.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="times-change-and-so-do-shortcuts"&gt;Times change, and so do shortcuts&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms"&gt;SSMS v 17.2&lt;/a&gt; brought some improvements for Intellisense: it now works against Azure SQL Database!&lt;/p&gt;
&lt;p&gt;It also appears to have changed the shortcut chord to toggle Intellisense on and off, though. This is now the chord: CTRL + B, CTRL + I.&lt;/p&gt;
&lt;p&gt;So now I&amp;rsquo;ll remember this as &amp;ldquo;Control Baffling Intellisense,&amp;rdquo;  I guess.&lt;/p&gt;
&lt;p&gt;Or you can pick whatever you favorite &amp;ldquo;B&amp;rdquo; word is ;)&lt;/p&gt;
&lt;h2 id="want-more-ssms-tips"&gt;Want more SSMS Tips?&lt;/h2&gt;
&lt;p&gt;Check out the videos, wallpaper, and cheat sheet my &lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;free online course, SSMS Shortcuts &amp;amp; Secrets&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How Do You Stay Motivated? (Dear SQL DBA Episode 47)</title><link>https://kendralittle.com/2017/09/01/how-do-you-stay-motivated-dear-sql-dba-episode-47/</link><pubDate>Fri, 01 Sep 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/09/01/how-do-you-stay-motivated-dear-sql-dba-episode-47/</guid><description>&lt;p&gt;Over the years, readers have asked me: &amp;ldquo;How do you stay motivated?&amp;rdquo; Sticking with a learning plan, blogging, or becoming a public speaker isn&amp;rsquo;t easy.&lt;/p&gt;
&lt;p&gt;In this 15 minute episode, I share how I think about motivation and what keeps me going.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now or read the transcript below? Listen on the go! This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/dAYNCgtvBj4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;Welcome to Dear SQL DBA, a podcast and YouTube show for SQL Server database administrators and developers. I&amp;rsquo;m Kendra Little from LittleKendra.com.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;m talking about a question that I&amp;rsquo;ve gotten from a few people over the years. I&amp;rsquo;ve had folks ask me, &amp;ldquo;Hey Kendra, where do you get your motivation?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve gotten this question about where do I get the motivation to blog, or to teach, or to keep learning.&lt;/p&gt;
&lt;p&gt;Sometimes folks say things like, &amp;ldquo;I&amp;rsquo;ve tried to do this myself. I&amp;rsquo;ve created a learning plan for myself, and I get started, but I never seem to get anywhere. I constantly get sidetracked by normal work life or personal requirements or whatever comes up. How do I stay motivated?&amp;rdquo;&lt;/p&gt;
&lt;h3 id="motivation-isnt-something-that-you-just-have"&gt;Motivation isn&amp;rsquo;t something that you just have&lt;/h3&gt;
&lt;p&gt;Motivation isn&amp;rsquo;t a quality that you&amp;rsquo;re born with, and you can&amp;rsquo;t really be missing it. This is good news because if you feel like you lack motivation, it&amp;rsquo;s not like this is a component of yourself that you lack.&lt;/p&gt;
&lt;p&gt;I have found that for me, motivation is a combination of building habits and of starting over after failures. That&amp;rsquo;s really to me what motivation is, is this process of continuously getting myself to build up habits&amp;mdash; which is hard! I&amp;rsquo;m not saying this is easy.&lt;/p&gt;
&lt;h3 id="building-habits"&gt;Building habits&lt;/h3&gt;
&lt;p&gt;Continuously building up habits, and when I fail &amp;ndash;which is often &amp;ndash; when things don&amp;rsquo;t go right, brushing myself off and getting going again &amp;ndash; when we&amp;rsquo;re building habits it&amp;rsquo;s really tough! Because when we&amp;rsquo;re doing something like setting out a learning plan, or starting a blog, or we want to write a presentation &amp;ndash; we have to work on this regularly.&lt;/p&gt;
&lt;p&gt;We want to publish a blog post fairly often, so we need to have a habit of writing. For a learning plan we need to have a habit of studying regularly. For writing a presentation we&amp;rsquo;ve got to have a rehearsal and have a process of creating the presentation, and of getting ready to do it. A lot of times we can set out with the best intentions and set out a plan for how we&amp;rsquo;re gonna do this, and then we just we fall off of it. Something comes up and we can&amp;rsquo;t make the schedule.&lt;/p&gt;
&lt;p&gt;Then we miss it the next time, and the next thing you know we&amp;rsquo;ve got a calendar reminder that we just don&amp;rsquo;t pay any attention to. We aren&amp;rsquo;t keeping up.&lt;/p&gt;
&lt;p&gt;When I have a hard time building a habit, I say, &amp;ldquo;okay, what can I do to try to get this habit to take?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Maybe I am trying to take on too much at once. Maybe I need to break this thing I&amp;rsquo;m trying to do into a smaller chunk and define it more granularly. So maybe instead of doing a big learning plan for myself over a course of three months, maybe I&amp;rsquo;m going to take the first part of that plan and take it slowly over one month. Just break it into that chunk and try to complete that, and then give myself a rest after I do that. Or maybe I need to change my habit around.&lt;/p&gt;
&lt;p&gt;Maybe I&amp;rsquo;ve been trying to learn this with books, maybe I should try to learn this with an online course. Or maybe I am gonna change my learning plan to include going to webcasts by virtual chapters, or going to my local user group. Maybe there is a variable in there that I can try to build a habit around, and I can change it a little bit. I also sometimes with myself &amp;ndash; depending on what the habit is &amp;ndash; sometimes setting a deadline for myself helps me along with the habit.&lt;/p&gt;
&lt;p&gt;Is there something I can work into my life where I actually need to have this done by a certain point? If you want to become a teacher and a presenter, there are obviously easy ways to set deadlines for yourself. But even if you have something like a learning plan, maybe saying okay what I want to do with this learning plan is I want to be able to write up a summary of what I&amp;rsquo;ve learned by X Date. Maybe there&amp;rsquo;s even an accountability factor I can add in for myself where I am going to give a short presentation to my team about what I&amp;rsquo;ve learned, or I&amp;rsquo;m going to talk to my coworker &amp;ndash; and I&amp;rsquo;ve promised.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve said, &amp;ldquo;OK, I want to meet this deadline. Will you help me be accountable for this?&amp;rdquo; Friends can help keep us accountable. There&amp;rsquo;s a reason that for lots of things that are dependent on habits, like stopping smoking, and weight loss, and anything that&amp;rsquo;s a difficult habit to take on &amp;ndash; there&amp;rsquo;s a reason that support groups are a really popular part of formats to help you along. Because having a regular place where you meet with other people, and having people who you are accountable to, and who you can relate to, and talk about the habit that you&amp;rsquo;re building can be very very helpful.&lt;/p&gt;
&lt;h3 id="its-hard-to-build-habits-were-going-to-fail-sometimes-maybe-a-lot"&gt;It&amp;rsquo;s hard to build habits: we&amp;rsquo;re going to fail sometimes. Maybe a lot!&lt;/h3&gt;
&lt;p&gt;The thing with failure, though, is you that when we&amp;rsquo;re trying to build habits, and when we&amp;rsquo;re taking on other projects, every time we slip up, every time we don&amp;rsquo;t stay on our schedule, or don&amp;rsquo;t go along with the plan where we&amp;rsquo;re trying to build that habit, we feel a sense of failure.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;I&amp;rsquo;ve tried to start a blog six times, and yet again I feel really dumb because I put two posts up and I haven&amp;rsquo;t been writing in it.&amp;rdquo; There&amp;rsquo;s this tendency that most of us have to feel bad about ourselves because we you had a plan and we weren&amp;rsquo;t able to stick to that plan. There are feelings of embarrassment and guilt and the idea that this somehow reflects on ourselves.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Failure feelings&amp;rdquo; is how I think about these feelings of &amp;ldquo;Oh I suck.&amp;rdquo; You don&amp;rsquo;t necessarily have the ability to stop these. At least, I have never been able to tell those feelings to go away. I can&amp;rsquo;t just say I&amp;rsquo;m not gonna have those feelings: I&amp;rsquo;m gonna have those feelings whether I want them or not! I understand that they aren&amp;rsquo;t good for me, but I can&amp;rsquo;t make those feelings just go away.&lt;/p&gt;
&lt;p&gt;So I don&amp;rsquo;t try to stop them anymore, but I try to recognize that those are a pattern, and that a lot of those feelings of failure &amp;ndash; like when I when I am NOT able to establish a habit and when I can&amp;rsquo;t keep up with something &amp;ndash; those feelings are habitual, and they are gonna show up, but I don&amp;rsquo;t have to believe those feelings.&lt;/p&gt;
&lt;p&gt;Just because I&amp;rsquo;m having a feeling doesn&amp;rsquo;t mean that feeling is correct. It doesn&amp;rsquo;t mean that it&amp;rsquo;s right.&lt;/p&gt;
&lt;p&gt;I can recognize, &amp;ldquo;okay, I&amp;rsquo;m having this feeling. It&amp;rsquo;s temporary. I feel bad about this but what do I want to do?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have to believe what the feeling is telling me. I can remind myself, &amp;ldquo;Okay, I&amp;rsquo;m not not meeting the plan that I had. I&amp;rsquo;m not building this habit, and I feel bad about it. But what do I want to do? What do I want to do going forward?&amp;rdquo; Really, where we act and what we control is looking forward. I am constantly reminding myself to look forward and to make a plan a positive plan about what I can do. Negative failure feelings have never helped me at all. They&amp;rsquo;ve never helped motivate me. I have never been motivated by that feeling of, &amp;ldquo;I suck because I didn&amp;rsquo;t do what I set out to do.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;What I find is much more motivating is if I have a failure feeling, and I&amp;rsquo;m feeling kind of crappy, recognizing &amp;ndash; yeah I&amp;rsquo;m feeling I&amp;rsquo;m feeling kind of crappy. What do I want to do though? What do I want to do moving forward? I may or may not want to try the same thing again. I may want to try something slightly differently but focus on thinking about what are the steps I can take, and how do I want to change things up.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s fine that things didn&amp;rsquo;t work out and it&amp;rsquo;s kind of interesting to me&amp;hellip; one of the things that has particularly over the last year has stuck with me is, a quote from Oprah Winfrey. I never really watched the Oprah Show much, but I listened to a podcast about the making of the Oprah Winfrey Show. They talked about for a while that one of the real themes they had while Oprah was building her show and her eventual media empire, is they had this mantra of, &amp;ldquo;Stay in your own lane.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That phrase is a really powerful phrase. I think I&amp;rsquo;m probably 15 years late on this phrase, but it still works&amp;ndash; because self comparisons to other people make restarting after failure harder!&lt;/p&gt;
&lt;h3 id="avoid-comparisons"&gt;Avoid comparisons&lt;/h3&gt;
&lt;p&gt;Those feelings of feeling bad when something goes wrong, it can become really easy when you&amp;rsquo;re having those feelings of feeling crappy because you didn&amp;rsquo;t do what you wanted to do &amp;ndash; mentally you may want to go towards thoughts like, &amp;ldquo;I wish I was more like this other person, because it seems easier for them.&amp;rdquo; Of course we don&amp;rsquo;t see all the failures that they went through, and we don&amp;rsquo;t see all of the feelings they&amp;rsquo;ve had about it. We see this imaginary version of them.&lt;/p&gt;
&lt;p&gt;These self comparisons to other people don&amp;rsquo;t help us get back up and try again. They don&amp;rsquo;t motivate us at all.&lt;/p&gt;
&lt;p&gt;Instead, staying in our own lane is more about just saying, okay focus on yourself and what you can do. This also means that having negative conversations about other people isn&amp;rsquo;t good for motivation either.&lt;/p&gt;
&lt;p&gt;This is something that it took me a long time to recognize in my life: that indulging in putting other people down&amp;ndash; whether or not they deserve it is frankly irrelevant &amp;ndash; criticizing other and doing it in a way that&amp;rsquo;s anything but constructive and practical is bad for YOU. It may feel good at the time, may make us feel better, but this is actually a kind of comparing ourselves to other people. If other people are causing problems, it&amp;rsquo;s totally valid to make a practical plan to say how can we work together better, and try to make it better. But that involves youbeing honest and not gossiping about people.&lt;/p&gt;
&lt;p&gt;Avoid self comparison to other people, whether we are the one who is in the right or not. It&amp;rsquo;s just not helpful.&lt;/p&gt;
&lt;p&gt;Staying in our own lane is about having a forward focus about, what do I want to do, and what is my path? How am I going to start again? There gonna be times when we fall into these behavior patterns of negative feelings, or the behavior patterns of having negative conversations about others. Or comparing ourselves to others in any way.&lt;/p&gt;
&lt;p&gt;Recognizing, &amp;ldquo;oh, I&amp;rsquo;m doing that again. Okay, you know what, I should really focus on what am I gonna do and how am I gonna make my life more awesome. I want to do X, how am I gonna go about and do this better?&amp;rdquo;&lt;/p&gt;
&lt;h3 id="make-a-habit-of-re-focusing"&gt;Make a habit of re-focusing&lt;/h3&gt;
&lt;p&gt;Refocusing is so much more powerful, and will lead you much more into getting the things done that you want to get done.&lt;/p&gt;
&lt;p&gt;It is never too late to start again. You may have started a learning plan 20 times and stopped on the second day. That&amp;rsquo;s fine. That&amp;rsquo;s totally fine.&lt;/p&gt;
&lt;p&gt;Hey guess what? It&amp;rsquo;s actually cool that you started 20 times! You can start again.&lt;/p&gt;
&lt;p&gt;Change one thing about the way you&amp;rsquo;re gonna execute that plan, and start again. It may be the 21st time that you make it through the plan, and you realize, &amp;ldquo;oh, here&amp;rsquo;s what I need to be able to set out on learning something, for my plan, for myself, and make it work at this time in my life.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;What works for us at one point in our life may need to change to work for us a year or two later. I don&amp;rsquo;t have the same habits when it comes to blogging or writing presentations or learning or teaching that I did ten years ago, because different things work for me now. The world is different and my brain is different. Adapting as we move move on &amp;ndash; what adapting really is, is starting over when something stops working.&lt;/p&gt;
&lt;h3 id="the-secret-of-motivation-is--the-motivation-isnt-something-i-have-i-dont-have-motivation"&gt;The secret of motivation is &amp;hellip; the motivation isn&amp;rsquo;t something I have. I don&amp;rsquo;t have motivation.&lt;/h3&gt;
&lt;p&gt;Instead I have a set of habits that I&amp;rsquo;ve built up, and fairly frequently things about those habits stop working. They start falling off for me, and I have to say, &amp;ldquo;okay, how do I get back into this? How do I change something? How do I keep going? How do I do something cool now?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Because failure is something that doesn&amp;rsquo;t go away in life. We always have things that trip us up. We always have things that stop working. We always have starting over.&lt;/p&gt;
&lt;p&gt;One of the quotes that I heard in school that has really stuck with me over the years, and that changes meaning over my life, is a quote from Samuel Beckett. One of my school friends loved Samuel Beckett.&lt;/p&gt;
&lt;p&gt;The quote is &amp;ndash; I may not get it exactly right &amp;ndash; it&amp;rsquo;s, &amp;ldquo;Try again, fail again, fail better.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That sounds really negative at first. That sounds just like such a downer, that you have to try again fail again feel better.&lt;/p&gt;
&lt;p&gt;But the truth is that is what success is: success is trying again, and not believing in those bad feelings.&lt;/p&gt;
&lt;p&gt;Not falling prey to those comparisons. Or if we fall prey &amp;ndash; we can&amp;rsquo;t stop ourselves from falling prey to them &amp;ndash; but recognizing, &amp;ldquo;okay what I need to do is focus on making a plan and setting out again. I don&amp;rsquo;t have a guarantee that I&amp;rsquo;m gonna succeed, and I&amp;rsquo;m never going to get one because this is life. I may fail again but my goal is I&amp;rsquo;m gonna try to fail better.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;In its own way, I think that is inspiring and beautiful, and is all about this process we have of moving forward.&lt;/p&gt;
&lt;p&gt;Thank you so much for joining me for this week of Dear SQL DBA. I&amp;rsquo;m Kendra Little from LittleKendra.com, and I&amp;rsquo;ll see you again next week.&lt;/p&gt;</description></item><item><title>Why Did My Clever Index Change Backfire? (free video)</title><link>https://kendralittle.com/2017/08/30/why-did-my-clever-index-change-backfire-free-video/</link><pubDate>Wed, 30 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/30/why-did-my-clever-index-change-backfire-free-video/</guid><description>&lt;p&gt;I had a great time giving a session recently for the &lt;a href="http://www.pass.org/24hours/2017/summitpreview/Schedule.aspx"&gt;24 Hours of PASS - Summit Preview Edition&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="about-this-session"&gt;About This Session&lt;/h2&gt;
&lt;p&gt;My &lt;a href="http://www.pass.org/summit/2017/Sessions/Details.aspx?sid=67124"&gt;session at the SQL PASS Summit this year&lt;/a&gt; is on great index ideas that accidentally backfire&amp;hellip; and how you can avoid disaster! In this preview version, I talk about filtered indexes, indexed views, and indexed computed columns. You can watch the session here, and &lt;a href="http://www.pass.org/24hours/2017/summitpreview/Sessions/Details.aspx?sid=66925"&gt;download the scripts from the PASS Site&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/gGMoHrIlHVY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>You faked your resume... now what? (video with transcript)</title><link>https://kendralittle.com/2017/08/25/i-faked-my-resume-now-what/</link><pubDate>Fri, 25 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/25/i-faked-my-resume-now-what/</guid><description>&lt;p&gt;This week&amp;rsquo;s question from a reader: &amp;ldquo;How do I deal with interview questions asking about real-world scenarios when I&amp;rsquo;ve faked three years of experience on my resume?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Hear my answer in this 14 minute video.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: No time to watch right now or read the transcript below? Listen on the go! This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dear-sql-dba-podcast.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/8390KBn0PMo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-this-episode"&gt;Transcript of this episode&lt;/h2&gt;
&lt;p&gt;Welcome to Dear SQL DBA, a podcast and YouTube Show for SQL Server developers and database administrators. I&amp;rsquo;m Kendra Little.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve done the last couple episodes on interviewing and helpful tips for landing that SQL Server DBA job, and I got a related question this week.&lt;/p&gt;
&lt;p&gt;This question from a reader goes like this&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA, I&amp;rsquo;ve taken courses on becoming a SQL Server DBA recently, but I wasn&amp;rsquo;t getting any calls for interviews. It seems that there just aren&amp;rsquo;t opportunities out there for people who don&amp;rsquo;t have experience. So I added three years of fake experience to my resume saying I had worked as a DBA. Now I&amp;rsquo;m getting calls to screen me, but interviewers are asking me questions about real work scenarios. I&amp;rsquo;m very good at DBA work, but how do I prepare for these work scenario questions in interviews?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, this is an honest question. Sort of. I mean, it&amp;rsquo;s an honest question about being dishonest, right?&lt;/p&gt;
&lt;h3 id="once-you-start-lying-on-your-resume-its-hard-to-stop"&gt;Once you start lying on your resume, it&amp;rsquo;s hard to stop&lt;/h3&gt;
&lt;p&gt;There are a lot of people out there who lie on their resumes. We know this from the news: there are executives who get caught late in their careers having faked degrees. If you think about this, you&amp;rsquo;re like, &amp;ldquo;wow, how could this person who went so far be so dumb as to lie about this in the modern age?&amp;rdquo; Once you lie about something, you&amp;rsquo;re stuck with that lie because your resume is out there, or your LinkedIn profile that used to contain the lie is cached, or there is some evidence out there. Or someone in your network knows that you once said that you had an experience, or you had a degree, or you had a certification&amp;hellip; and it will catch up with you!&lt;/p&gt;
&lt;p&gt;In the modern world, once you start on this path of being dishonest, it is very hard to change it. People who do this often have it follow them for a very long time.&lt;/p&gt;
&lt;h3 id="lots-of-people-looking-for-dba-jobs-have-fake-experience-and-they-get-caught"&gt;Lots of people looking for DBA jobs have fake experience, and they get caught&lt;/h3&gt;
&lt;p&gt;There are a lot of people out there who look for DBA jobs and who lie about their experience. Or lie about their certifications, or have even cheated to get those certifications. When folks ask, &amp;ldquo;will a certification help with my career?&amp;rdquo; a big part of the reason that certifications don&amp;rsquo;t hold that much weight when it comes to hiring managers anymore is there is a history of a lot of people cheating on certifications. While it might become part of an overall successful package when you go through interviews, people are really going to want to make sure that you do have experience, and you do really know things. That&amp;rsquo;s the reason that just saying you have a certification isn&amp;rsquo;t good enough.&lt;/p&gt;
&lt;p&gt;For our questioner, and for for anyone else who&amp;rsquo;s in this boat &amp;ndash; because there are other people who do this! I know, because I&amp;rsquo;ve done a lot of phone screens: there are a lot of people who fake experience, and it becomes pretty obvious in the interview process. There are a couple things that you should know about the DBA job.&lt;/p&gt;
&lt;h3 id="1-faking-your-resume-means-youre-not-a-good-dba"&gt;1. Faking your resume means you&amp;rsquo;re not a good DBA&lt;/h3&gt;
&lt;p&gt;In fact you are NOT good at being a DBA. Our questioner said, &amp;ldquo;I am good at this SQL DBA stuff.&amp;rdquo; Actually you&amp;rsquo;re not, and it is the wrong job for you.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying this out of moral outrage, I&amp;rsquo;m saying this practically because the essence of the DBA job, in fact the most important core thing about being a DBA is about being accountable when things go wrong.&lt;/p&gt;
&lt;p&gt;As a SQL Server DBA, this isn&amp;rsquo;t just about knowledge of what page size the SQL Server uses, or SQL Server internals. The core job of the DBA is to be the person who&amp;rsquo;s answering questions like: &amp;ldquo;Why were we offline?&amp;rdquo; &amp;ldquo;Why is the data wrong?&amp;rdquo; &amp;ldquo;Why does this customer say we lost data?&amp;rdquo; &amp;ldquo;Why didn&amp;rsquo;t this change go as planned?&amp;rdquo; &amp;ldquo;You said it would be like X but it didn&amp;rsquo;t go that way, why?&amp;rdquo; &amp;ldquo;What happened to those indexes?&amp;rdquo; &amp;ldquo;Why do we have corruption?&amp;rdquo; &amp;ldquo;Why didn&amp;rsquo;t we find this earlier?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;A core &amp;ndash; in fact I think really THE most important thing about being a DBA &amp;ndash; is to be honest and accountable about what happened, and what we should do in the future. As a DBA, if when things get hot and when things get under pressure, if your impulse is to make something up in the moment &amp;ndash; to say something to get the heat off you &amp;ndash; it&amp;rsquo;s going to go really really badly for you. It&amp;rsquo;s going to be a time where you lose your job, where you have a hard time getting another job, and you get really really burnt in terms of being able to succeed.&lt;/p&gt;
&lt;p&gt;As a DBA you need to be able to tell the truth even when it&amp;rsquo;s really unpleasant, and doesn&amp;rsquo;t work in your favor. In the long run that always works better for you as a DBA, but in the short term it is really really hard, and if your inclination is to lie on your resume about your experience that shows that you&amp;rsquo;re not suited to the most core, important things about being a DBA.&lt;/p&gt;
&lt;h3 id="2-it-usually-takes-a-long-time-to-land-a-dba-job"&gt;2. It usually takes a long time to land a DBA job&lt;/h3&gt;
&lt;p&gt;The second thing you should know, is that yes, it does take a long time to get a DBA job. There are actually a lot of good reasons for that. This isn&amp;rsquo;t a new thing that it&amp;rsquo;s hard to get a job as a DBA. It&amp;rsquo;s it&amp;rsquo;s been hard to get a job as a DBA for a long time.&lt;/p&gt;
&lt;p&gt;When you think about data, usually data is one of a company&amp;rsquo;s most valuable assets. If they lose data, or the data is massively incorrect, or even just if a database is offline for a long time, this often can be a business ending event. Not just expensive, but so expensive that the company can&amp;rsquo;t proceed.&lt;/p&gt;
&lt;p&gt;This is so critical that they want people managing the data who have not only knowledge about how to keep the data online, but also experience at handling things when they go wrong, and experience at planning successful changes, and preventing things from going wrong. Experience in a lot of processes. They also someone who has experience being accountable.&lt;/p&gt;
&lt;p&gt;I had a lot of education, I had a Bachelor&amp;rsquo;s degree and a Master&amp;rsquo;s degree, and my path to becoming a DBA took more than five years. When I was in graduate school, I discovered that I loved working with data. I had a work-study job where I got to work with Access databases, and I found it fascinating. After I got my degree, I wanted to do it full-time, but I had to move through so many different jobs because no one would hire me as a DBA. I didn&amp;rsquo;t have the experience, and frankly I didn&amp;rsquo;t have the accountability. So I worked through all sorts of different jobs and I would always look for jobs where I could work with data, where I could get a little more experience: understanding processes, understanding how different teams work together. Finally I got a job at a software company, but I still wasn&amp;rsquo;t a DBA.&lt;/p&gt;
&lt;p&gt;I had to very carefully work myself to a place where I had enough experience that I could get a job as a DBA, and I still had to go from a relatively secure full-time job to a contracting job as an DBA. but it was worth it to me because as I progressed through that, it was still what I enjoyed the most. It was still what I wanted to do. But for a lot of people, there might be places along this journey where along the way you find out you actually like doing something else better. That&amp;rsquo;s totally valid.&lt;/p&gt;
&lt;p&gt;But I needed all of the experience that I got on this five year journey to finally getting to be DBA. How software development works in different situations; how you can make it work the best for your data; how you can manage changes with different types of software development: these are things I learned. How I could design changes and minimize risk; how to react when things go wrong &amp;ndash; and that is not a simple thing to learn about, how to react when things go wrong. Over these five years, I saw a lot of different things go wrong, and I got to see different teams reacted to that, how they started the approach, how flexible they were, how they communicated during it, how they followed it up on it, what went well, what should change in the future. I mean it was all stuff that when I finally did get that DBA job I used it all.&lt;/p&gt;
&lt;p&gt;And right now, for our questioner: when things are wrong your reaction is to fake it.&lt;/p&gt;
&lt;h3 id="it-takes-a-while-to-change-something-like-this"&gt;It takes a while to change something like this&lt;/h3&gt;
&lt;p&gt;Now, it&amp;rsquo;s it&amp;rsquo;s possible that you could learn something different, right? I mean it&amp;rsquo;s not like if you lie once in your life and you&amp;rsquo;re doomed forever, and you&amp;rsquo;re never going to be able to be a DBA. I&amp;rsquo;m not saying that.&lt;/p&gt;
&lt;p&gt;But right now, your reaction is to fake it and to be a successful DBA you&amp;rsquo;re really gonna have to train that out of you, because that will backfire on you, and it will just burn you over and over. Eventually it will just get you out of this career.&lt;/p&gt;
&lt;p&gt;But to change things, and to get the experience needed and really move away from that, so when things go wrong you think of multiple viable options that you can do that have nothing to do with faking it &amp;ndash; that&amp;rsquo;s going to take possibly longer than five years. You&amp;rsquo;re likely to get derailed before you get there. Honesty is just an essential essential business skill for DBA. If you&amp;rsquo;re starting out at a place where you&amp;rsquo;re not in the honesty range and you lack this essential skill, I would honestly look elsewhere just because of efficiency. Getting to the point where you can be creative and be honest all the time is going to be a really big leap in addition to learning everything else that you need to learn you can get there. It may just take a very very long time, and I would focus on driving all of that impulse to fake it out of all of your responses to life, because that is just gonna truly poison your career as a DBA.&lt;/p&gt;
&lt;h3 id="what-about-exaggeration"&gt;What about exaggeration?&lt;/h3&gt;
&lt;p&gt;For some folks, you may be like, &amp;ldquo;Well, what about exaggeration?&amp;rdquo; A lot of people do exaggerate on their resumes. When you are building your resume, if you know that you&amp;rsquo;re exaggerating about something don&amp;rsquo;t do it. Don&amp;rsquo;t inflate numbers, don&amp;rsquo;t put things on your resume that aren&amp;rsquo;t true. For other people, it can be a little trickier: some people have a hard time writing their resume because even just stating the truth feels like bragging to them. But a lot of times if you&amp;rsquo;re one of those people and you&amp;rsquo;re self-conscious, and you&amp;rsquo;re just trying to even state your accomplishments, and you&amp;rsquo;re like, &amp;ldquo;oh but I&amp;rsquo;m worried that I&amp;rsquo;m being dishonest,&amp;rdquo; find someone to work with on your resume. Someone honest&amp;ndash; you&amp;rsquo;re not hiring someone to fake things for you&amp;ndash; but but find someone who to help you translate your experience into resume versions of that statement, which may at first feel like bragging to you.&lt;/p&gt;
&lt;p&gt;But bragging is fine. Dishonesty is NOT fine. On a resume, bragging is what really it&amp;rsquo;s all about. You want to keep it real, you don&amp;rsquo;t want to brag about things that didn&amp;rsquo;t happen, but you do want to &amp;ndash; on a resume you&amp;rsquo;re saying, &amp;ldquo;Hey, here&amp;rsquo;s the cool stuff that I did,&amp;rdquo; and you want to be upfront and you want to be clear about that. Finding someone to work with you on your resume who you can talk things out with, and get a short phrasing of things that is still accurate, other people can help you with that. Maybe it&amp;rsquo;s a friend, maybe it&amp;rsquo;s a professional resume writer, maybe it&amp;rsquo;s a past colleague or a mentor. Other folks can help you with that as well. I do want to distinguish that feeling like you&amp;rsquo;re bragging is absolutely not the same thing necessarily as being dishonest.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The truth is we all know when we&amp;rsquo;re lying, and that&amp;rsquo;s the trait that just won&amp;rsquo;t serve you as a DBA.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="thanks-for-the-question"&gt;Thanks for the question&lt;/h3&gt;
&lt;p&gt;I would like to thank my questioner for an honest question. I hope you take this feedback that I really I really don&amp;rsquo;t think this is the career for you&amp;ndash; I hope you take that to heart, and I do wish you the best in your career, wherever it takes you. But yeah as a DBA really that accountability is just such a critical, critical business skill.&lt;/p&gt;
&lt;p&gt;Thanks for joining me this week for Dear SQL DBA. I&amp;rsquo;m Kendra Little, and I&amp;rsquo;ll see you again next week.&lt;/p&gt;</description></item><item><title>sp_query_store_flush_db, Query Store, and Backups</title><link>https://kendralittle.com/2017/08/23/sp_query_store_flush_db-query-store-and-backups/</link><pubDate>Wed, 23 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/23/sp_query_store_flush_db-query-store-and-backups/</guid><description>&lt;p&gt;One of the cool things about Query Store is that you can back it up with the database.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t perfect for every situation, because you must back up the &lt;em&gt;whole&lt;/em&gt; database. If you&amp;rsquo;ve got a multi-terabyte database, your Query Store isn&amp;rsquo;t super portable! But still, it&amp;rsquo;s great to have an option.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Quail-E-Store-e1503351829105.jpg"
alt="An old fashioned Qual-E Store" width="230"&gt;
&lt;/figure&gt;
There are a few things worth knowing about how Query Store works with backups and restores.&lt;/p&gt;
&lt;h2 id="if-query-store-is-readwrite-when-you-back-up-a-database-it-restores-the-same-way"&gt;If Query Store is read/write when you back up a database, it restores the same way&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say your production database is collecting data with Query Store. When you restore a full backup elsewhere, the Query Store data from production restores with it, &lt;em&gt;and&lt;/em&gt; Query Store stays in the same read-write state.&lt;/p&gt;
&lt;p&gt;Maybe you want this, maybe you don&amp;rsquo;t!&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a good idea to check if Query Store is enabled and its settings after a restore. You can do this simply with the following query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_query_store_options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a database level query, so use the database before you run it.&lt;/p&gt;
&lt;h2 id="if-you-want-to-back-up-very-recent-activity-in-query-store-run-syssp_query_store_flush_db-before-the-backup"&gt;If you want to back up very recent activity in Query Store, run sys.sp_query_store_flush_db before the backup&lt;/h2&gt;
&lt;p&gt;Query Store was designed to be clever, and to minimize its impact on your performance. Query Store only flushes its data from memory to disk periodically. You get to control this by setting the data flush interval in the Query Store settings for a database. (Read more about this &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/how-query-store-collects-data#query-processing"&gt;in Microsoft Documentation here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;The default value for Query Store data flush is 15 minutes. That means that in the case of a crash, you might lose up to around 15 minutes of activity.&lt;/p&gt;
&lt;p&gt;Even if you&amp;rsquo;ve lowered this, you might want to make sure that a backup contains the very latest activity, particularly if you&amp;rsquo;re taking the backup to get Query Store data for someone to look at.&lt;/p&gt;
&lt;p&gt;You can manually flush Query Store data to disk before the backup by running the built in procedure, &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-query-store-flush-db-transact-sql"&gt;sys.sp_query_store_flush_db&lt;/a&gt; in that database.&lt;/p&gt;
&lt;h2 id="want-to-play-around-with-some-sample-code"&gt;Want to play around with some sample code?&lt;/h2&gt;
&lt;p&gt;Here is some very simple code that creates a database, enabled query store, and lets you &lt;a href="https://gist.github.com/LitKnd/eaff2090070726e314b62f6c177886ea"&gt;easily play around with and test sys.sp_query_store_flush_db&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How to Get Email Notifications for TSQLTuesday</title><link>https://kendralittle.com/2017/08/21/how-to-get-email-notifications-for-tsqltuesday/</link><pubDate>Mon, 21 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/21/how-to-get-email-notifications-for-tsqltuesday/</guid><description>&lt;p&gt;Lots of us want to write for TSQL Tuesday, but aren&amp;rsquo;t always on Twitter at the right time each month to see when the announcement comes out &lt;a href="https://twitter.com/hashtag/tsql2sday?lang=en"&gt;using the #tsql2sday hash tag&lt;/a&gt;. And maybe we have an RSS feed set up, but we often get behind on a big pile of posts to read. (Guilty!)&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tsql2sdayrss.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="i-want-an-email"&gt;I want an email!&lt;/h2&gt;
&lt;p&gt;Wouldn&amp;rsquo;t it be nice to get a notification in your inbox when a new topic is announced, the week before TSQLTuesday itself?&lt;/p&gt;
&lt;p&gt;You can set this up in two minutes by configuring a free IFTTT applet to email you when a new post goes into the RSS feed for &lt;a href="http://tsqltuesday.com/"&gt;TSQLTuesday.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;IFTTT, or &amp;ldquo;If-This-Then-That&amp;rdquo; has been around since 2010. I first used it in the early days of the service when I was looking for a place to rent in a competitive market, and wanted to get notified of new postings on Craigslist. It&amp;rsquo;s very handy for custom notifications of all sorts.&lt;/p&gt;
&lt;h2 id="how-to-set-it-up"&gt;How to set it up&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s how to set up your email:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a free account on &lt;a href="https://ifttt.com/"&gt;https://ifttt.com/&lt;/a&gt;. Your account settings are where you tell it your email address.&lt;/li&gt;
&lt;li&gt;Add the RSS feed to Email applet: &lt;a href="https://ifttt.com/applets/147561p-rss-feed-to-email"&gt;https://ifttt.com/applets/147561p-rss-feed-to-email&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;Click &amp;lsquo;Turn on&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Optionally type a feed name into the &lt;em&gt;top&lt;/em&gt; box&lt;/li&gt;
&lt;li&gt;Paste the feed URL into the &lt;em&gt;bottom&lt;/em&gt; box: http://tsqltuesday.com/feed/&lt;/li&gt;
&lt;li&gt;Click save&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:  I made a mistake in the original run of this post in the setup of the IFTTT applet. This is the corrected version of the instructions, and it worked &amp;ndash; the email announcing TSQL Tuesday came through for me.&lt;/p&gt;</description></item><item><title>Recruiters, Nerves, and Saying No in Interviews (video with transcript)</title><link>https://kendralittle.com/2017/08/17/interview-advice-from-the-sql-server-community-video-or-transcript/</link><pubDate>Thu, 17 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/17/interview-advice-from-the-sql-server-community-video-or-transcript/</guid><description>&lt;p&gt;In this episode of &amp;ldquo;Dear SQL DBA&amp;rdquo;, I talk about three articles written by members of the SQL Server community on interviewing that I can&amp;rsquo;t stop thinking about.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Playing the Third Party Recruiter Game&amp;rdquo;, by Adam Machanic - &lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2017/08/08/playing-the-third-party-recruiter-game-t-sql-tuesday-093.aspx"&gt;read it here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;I Hate Interviews&amp;rdquo;, by Rob Sewell - &lt;a href="https://sqldbawithabeard.com/2017/08/08/i-hate-interviews-tsql2sday/"&gt;read it here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Learning to say &amp;lsquo;No&amp;rsquo;&amp;rdquo; by Mark Broadbent - &lt;a href="https://tenbulls.co.uk/2017/08/08/learning-to-say-no/"&gt;read it here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this 8 minute video, I talk about why I think these posts are so great (without spoiling everything). If you&amp;rsquo;re short on time, check out the transcript below the video, &lt;a href="http://dearsqldba.libsyn.com/"&gt;listen to this on the go as a podcast&lt;/a&gt;, or just follow the link to read the articles yourself.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/9ppAM0Uc5M0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-the-video"&gt;Transcript of the video&lt;/h2&gt;
&lt;p&gt;Today I&amp;rsquo;m talking about interview advice from the SQL Server community. We&amp;rsquo;ll be talking about recruiters, nerves, and saying &amp;ldquo;no&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I recently hosted TSQLTuesday, which is a monthly blogging event. I got to pick the topic. The topic I picked was interview patterns and anti-patterns and I wanted to open it up: you didn&amp;rsquo;t have to talk about both patterns and anti-patterns. I really wanted to just get advice from folks about interviewing.&lt;/p&gt;
&lt;p&gt;There are some fantastic posts! I really enjoyed reading through all of them and a lot of the advice works for any sort of developer or IT professional. It&amp;rsquo;s not all SQL Server specific.&lt;/p&gt;
&lt;p&gt;There were three of these posts that really stuck with me. Like the kind of blog post that you read and I just couldn&amp;rsquo;t stop thinking about them, they really resonated with me.&lt;/p&gt;
&lt;p&gt;I am sharing those three posts with you in this episode. I&amp;rsquo;m not gonna spoil the posts for you: what I&amp;rsquo;m going to do is I&amp;rsquo;m going to tell you where you can find them and talk about why I think they&amp;rsquo;re such outstanding posts and how I think they can help you.&lt;/p&gt;
&lt;h3 id="playing-the-third-party-recruiter-game-by-adam-machanic"&gt;&amp;ldquo;Playing the Third Party Recruiter Game&amp;rdquo;, by Adam Machanic&lt;/h3&gt;
&lt;p&gt;The first post is by Adam Machanic. He wrote this post on SQLBlog.com - &lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2017/08/08/playing-the-third-party-recruiter-game-t-sql-tuesday-093.aspx"&gt;read it here&lt;/a&gt;. This post is called &amp;ldquo;Playing the third party recruiter game.&amp;rdquo; In this post Adam tells you how recruiters make money, and more importantly what that means about your relationship with the third party recruiter. He gives you really practical advice on how to vet the recruiter and to make sure that you&amp;rsquo;re working with the right recruiters because there&amp;rsquo;s a lot of recruiters out there.&lt;/p&gt;
&lt;p&gt;He gives you real world examples of how if you work with the wrong recruiter it can end up burning you, so he tells you how to vet the recruiter and make sure that you&amp;rsquo;re avoiding the ones that can lead you into disappointing situations that aren&amp;rsquo;t great for you. He tells you why you should be interviewing your recruiter and how to go about doing that in a practical way that won&amp;rsquo;t be weird or awkward. He gives you really specific questions to talk through in the interview and lets you know how the process should be going.&lt;/p&gt;
&lt;p&gt;This is really great insight, because the first time you work with a recruiter, you just don&amp;rsquo;t have a good idea of how this should work! If you&amp;rsquo;ve been working with the wrong recruiters you probably don&amp;rsquo;t know how much better it could be.&lt;/p&gt;
&lt;p&gt;So check out Adam Machanic&amp;rsquo;s post on SQLBlog, which is titled &amp;ldquo;Playing the third party recruiter game,&amp;rdquo; if you&amp;rsquo;re going to work with recruiters. They really can help you land great jobs. This is great essential reading to help you find the right recruiter and get the most out of the situation.&lt;/p&gt;
&lt;h3 id="i-hate-interviews-by-rob-sewell"&gt;&amp;ldquo;I Hate Interviews&amp;rdquo;, by Rob Sewell&lt;/h3&gt;
&lt;p&gt;Another fantastic post is written by Rob Sewell on SQLDBAWithABeard.com. &lt;a href="https://sqldbawithabeard.com/2017/08/08/i-hate-interviews-tsql2sday/"&gt;Read it here.&lt;/a&gt; I love that URL. Head to Rob&amp;rsquo;s blog and you&amp;rsquo;ll find this post, it&amp;rsquo;s called &amp;ldquo;I hate interviews,&amp;rdquo; which i think is just a fantastic title, right? Super memorable, right to the point, and Rob explains why he hates interviews. He is overcome with nerves.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t just a DBA thing: he explains how interviews have made him nervous his whole life. He does it in a way where I felt like I was right there with him. It&amp;rsquo;s a great post because I felt like a friend was telling me about difficult times that he had with entertaining stories, and he helped me understand systems that he&amp;rsquo;s put in place that have helped him manage this and be able to deal with interviews.&lt;/p&gt;
&lt;p&gt;He still hates interviews and this is this is how things work in the real world: we can&amp;rsquo;t always just make nerves go away. We have to learn how when we have things in life that make us really nervous or make us anxious, we have to learn how to get good at them even if that nervousness can&amp;rsquo;t be vanquished.&lt;/p&gt;
&lt;p&gt;So he manages this. He gives really practical real-world tips, but the big picture is: there is preparation, practice, knowledge, and distraction. He talks about exactly how he works these out so that he can do well at interviews which don&amp;rsquo;t come natural to him.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s a really great honest post that&amp;rsquo;s going to help so many people, because there&amp;rsquo;s a lot of us who get really, really nervous and interview situations.&lt;/p&gt;
&lt;p&gt;Thank you so much Rob for writing this excellent post.&lt;/p&gt;
&lt;h3 id="learning-to-say-no-by-mark-broadbent"&gt;&amp;ldquo;Learning to say &amp;lsquo;No&amp;rsquo;&amp;rdquo; by Mark Broadbent&lt;/h3&gt;
&lt;p&gt;Mark Broadbent also wrote a really honest, helpful post about a different type of problem with interviews. Mark&amp;rsquo;s site is TenBulls.co.uk. and Mark&amp;rsquo;s post is called &amp;ldquo;Learning to say no.&amp;rdquo; &lt;a href="https://tenbulls.co.uk/2017/08/08/learning-to-say-no/"&gt;Read it here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In Mark&amp;rsquo;s post, he explains how he had this pattern in his life where he was having these stressful jobs that caused him a lot of anxiety: that kind of thing where you&amp;rsquo;re going to work and you&amp;rsquo;re dreading the stress and negative situations you&amp;rsquo;re going to be in all day. He got to a point where he thought back on it, and he recognized that this was a pattern, and that his own actions had &amp;ndash; this this wasn&amp;rsquo;t just a coincidence, he was in this pattern for a reason.&lt;/p&gt;
&lt;p&gt;He realized he had never turned down a job offer. I read Mark&amp;rsquo;s post, and I thought about this, and I remembered a time in my career when I would only ever interview for a job if I was in a stressful situation, and I was really burnt out. I realized that I never saw this pattern at that time in my career as clearly as Mark points it out. If I&amp;rsquo;d had that moment of realization back when I was in that pattern, wow, maybe I could have changed things!&lt;/p&gt;
&lt;p&gt;Mark changed things for himself by setting himself a challenge: he set himself a challenge of turning down a job offer. He explains in this post how he went about that and how it changed his career.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not gonna spoil how it turned out, but I think it&amp;rsquo;s a really interesting compelling post that&amp;rsquo;s absolutely worth reading over on Mark Broadbent&amp;rsquo;s blog on TenBulls.co.uk.&lt;/p&gt;</description></item><item><title>Interviewing Patterns &amp; Anti-Patterns: Advice from the SQL Server Community</title><link>https://kendralittle.com/2017/08/14/interviewing-patterns-anti-patterns-advice-from-the-sql-server-community/</link><pubDate>Mon, 14 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/14/interviewing-patterns-anti-patterns-advice-from-the-sql-server-community/</guid><description>&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sqlworkbooks-interview-too-selective.png"&gt;
&lt;/figure&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m glad I picked interviewing as the topic of TSQL Tuesday #93, because people wrote posts chock full of great advice and funny stories. Get ready to learn, be amazed, and laugh out loud as you read these posts, which I&amp;rsquo;ve indexed by the author&amp;rsquo;s first name. Don&amp;rsquo;t blame these authors for the dorky jokes in the cartoons, though. That&amp;rsquo;s all my fault.&lt;/p&gt;
&lt;h2 id="community-contributions"&gt;Community Contributions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Aaron Bertrand&lt;/strong&gt; is &amp;ldquo;&lt;a href="https://blogs.sentryone.com/aaronbertrand/looking-back-at-bad-interviews/"&gt;looking back at bad interviews&lt;/a&gt;.&amp;rdquo; In the comments, I give a sure-fire way for you to handle any technical interview questions you don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adam Machanic&lt;/strong&gt; talks about &amp;ldquo;&lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2017/08/08/playing-the-third-party-recruiter-game-t-sql-tuesday-093.aspx"&gt;playing the third-party recruiter game&lt;/a&gt;.&amp;rdquo; He gives you real world stories where he&amp;rsquo;s been burned and tips on how to identify the right recruiters who will represent you well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arun Sirpal&lt;/strong&gt; (aka BlobEater, love that name) gives three tips for candidates, and a story of a &lt;em&gt;very curious interview challenge&lt;/em&gt; in &amp;ldquo;&lt;a href="https://blobeater.blog/2017/08/08/interviews-and-oranges/"&gt;Interviews and Oranges&lt;/a&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Brent Ozar&lt;/strong&gt; writes about &amp;ldquo;&lt;a href="https://ozar.me/2017/08/the-dba-job-i-turned-down-tsql2sday/"&gt;the DBA Job I Turned Down&lt;/a&gt;,&amp;rdquo; which encouraged an especially close relationship between some team members.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dan Clemens&lt;/strong&gt; thinks of two main things when it comes to interviews: &lt;a href="https://drcdba.com/2017/08/08/tsql-tuesday-93-interviewing-patterns-anti-patterns/"&gt;Passion and Aptitude&lt;/a&gt;. Read the story of how Dan developed his interview process when he was hiring a Junior DBA, and how the successful candidate landed the job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deb the DBA&lt;/strong&gt; writes about how interviewing is a lot like casting in &amp;ldquo;&lt;a href="https://debthedba.wordpress.com/2017/08/08/t-sql-tuesday-93-auditioning-for-the-job/"&gt;Auditioning for the Job&lt;/a&gt;.&amp;rdquo; She also links to a list of reasons why you didn&amp;rsquo;t get the part &amp;ndash; and it&amp;rsquo;s GOLD.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sqlworkbooks-interview-what-is-running.png"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Doug Lane&lt;/strong&gt; tells you &lt;a href="https://www.sqltheater.com/2017/08/08/unforgettable-job-candidate/"&gt;how to be an unforgettable job candidate&lt;/a&gt;. It&amp;rsquo;s good advice - Doug is &lt;em&gt;really good&lt;/em&gt; at being memorable in job applications!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Duncan Greaves&lt;/strong&gt; suggests that we think about interviews as a form of human ritual, and gives &lt;a href="https://informationwithinsight.com/2017/08/08/recruitment-interview-patterns-and-anti-patterns/"&gt;tips to help you exhibit the behaviors that will land you a job&lt;/a&gt;. He ends with an important word of advice about coffee.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ewald Cress&lt;/strong&gt; writes about, &amp;ldquo;&lt;a href="http://sqlonice.com/tsql-tuesday-93-the-buzzword-arms-race/"&gt;The buzzword arms race&lt;/a&gt;&amp;rdquo; - and gives you a tip on how to defuse such an arms race as a candidate,  if you ever end up in that situation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Garland MacNeill&lt;/strong&gt; writes about interviewing questions that frustrate him, and where he thinks your focus should be as a candidate in &amp;ldquo;&lt;a href="https://sqlmac.com/t-sql-tuesday-93-interview-fails/"&gt;Interview Fails&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ginger Grant&lt;/strong&gt; gives an overview of different types of table design (which is great reading if you&amp;rsquo;re worried about being asked this in an interview), and tells a story of &lt;a href="http://www.desertislesql.com/wordpress1/?p=1882"&gt;a very special style of schema design&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;John Deardurff&lt;/strong&gt; highlights the importance of asking questions&amp;ndash; and gives you ideas for questions to ask&amp;ndash; in &amp;ldquo;&lt;a href="http://john.deardurff.com/interviewquestions/"&gt;Interviews are a Two-Way Street&lt;/a&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jeff Mlakar&lt;/strong&gt; gives you tips for before the interview, during the interview, and after the interview in &amp;ldquo;&lt;a href="http://www.mlakartechtalk.com/t-sql-tuesday-93-interview-get-help"&gt;Interview get-help&lt;/a&gt;.&amp;rdquo; His post-interview advice gives you specific actions that can help keep you going, even in frustrating times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jens Vestergaard&lt;/strong&gt; writes about his experience designing technical interviews for candidates when he needed to screen for a range of different skills.  I particularly enjoyed &lt;a href="http://t-sql.dk/?p=2096"&gt;reading about his favorite questions to ask people&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;K Brian Kelly&lt;/strong&gt; sees interviewing as an information exchange, and tells you &lt;a href="https://truthsolutions.wordpress.com/2017/08/08/tsql2sday-interviewing-patterns/"&gt;why you should be honest, but only exchange information up to a point&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kendra Little&lt;/strong&gt; (that&amp;rsquo;s me!) tells a story about &lt;a href="https://kendralittle.com/2017/08/08/interview-patterns-anti-patterns-tsql-tuesday-93/"&gt;a heartbreaking flop of an interview&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kenneth Fisher&lt;/strong&gt; applies the concept of a &amp;ldquo;love bank&amp;rdquo; to an interview. I know that got your interest, &lt;a href="https://sqlstudies.com/2017/08/08/interview-patterns-and-anti-patterns-combined/"&gt;read on&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sqlworkbooks-interview-octomizer.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Kevin3NF&lt;/strong&gt; gives us rules for candidates, rules for interviewers, and stories from his own interviewing career &amp;ndash; with a highlight outside of a Taco Bell! &lt;a href="http://dallasdbas.com/interview-tips/"&gt;Make a run for the interviewing border&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mark Broadbent&lt;/strong&gt; writes an honest post about his professional experiences with the frying pan and the frier and talks about &amp;ldquo;&lt;a href="https://tenbulls.co.uk/2017/08/08/learning-to-say-no/"&gt;learning to say no&lt;/a&gt;&amp;rdquo; as a candidate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Matt Gordon&lt;/strong&gt; challenges us to challenge our implicit bias in &amp;ldquo;&lt;a href="https://sqlatspeed.com/2017/08/08/t-sql-tuesday-93-shock-and-subtlety-of-sexist-interviewers/"&gt;Shock and Subtlety of Sexist Interviewers&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Matthew McGiffen&lt;/strong&gt; tells you, &amp;ldquo;&lt;a href="https://matthewmcgiffen.com/2017/08/08/how-to-be-a-bad-interviewer/"&gt;how to be a bad interviewer&lt;/a&gt;&amp;rdquo; in this list of real-world anti-patterns for employers. If you&amp;rsquo;re hiring a candidate, this is a great list to review: it&amp;rsquo;s easy to fall into some of these patterns, and they &lt;em&gt;will&lt;/em&gt; turn off great candidates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nate Johnson&lt;/strong&gt; talks about why it&amp;rsquo;s hard to interview DBAs, then gives three examples of interview questions for DBAs. &lt;a href="https://natethedba.wordpress.com/2017/08/07/tsql-tuesday-93-interviews/"&gt;Try them out&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Niko Neugebaur&lt;/strong&gt; tells the story of two job interviews: &lt;a href="http://www.nikoport.com/"&gt;the one he had to skip, and the one he did not get&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mike Walsh&lt;/strong&gt; writes about a magic phrase you should know in an &amp;ldquo;&lt;a href="https://straightpathsql.com/archives/2017/08/important-lesson-job-interview-tsql2sday/"&gt;important lesson during a job interview&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rob Farley&lt;/strong&gt; writes about how he got out of interview loops altogether in &amp;ldquo;&lt;a href="http://sqlblog.com/blogs/rob_farley/archive/2017/08/08/interviews-and-niches.aspx"&gt;Interviews and niches&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rob Sewell&lt;/strong&gt; &lt;a href="https://sqldbawithabeard.com/2017/08/08/i-hate-interviews-tsql2sday/"&gt;hates interviews&lt;/a&gt;. If interviews make you nervous, &lt;em&gt;read this post&lt;/em&gt;. Rob has great, practical tips on how to build your interview skills.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Robert Davis&lt;/strong&gt; highlights the importance of asking questions as a job candidate (and gives you some of the questions &lt;em&gt;he&lt;/em&gt; asks) in his entertaining post, &amp;ldquo;&lt;a href="http://sqlsoldier.net/wp/sqlserver/tsqltuesday933jobsididnttakeand1idid"&gt;3 jobs I didn&amp;rsquo;t take and 1 I did&lt;/a&gt;.&amp;rdquo; I love his closing story of the moment he realized that a job was right for him.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Robert Preseau&lt;/strong&gt; works as a data generalist and problem solver. He writes about &lt;a href="http://www.databythebeach.com/tell-me-about-a-time/"&gt;why that&amp;rsquo;s a tricky job when it comes to interviews&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shane O&amp;rsquo;Neill&lt;/strong&gt; &lt;a href="https://nocolumnname.wordpress.com/2017/08/08/tsql-tuesday-93-interviewing-patterns-anti-patterns"&gt;raises thought provoking questions&lt;/a&gt;, both for the company hiring a DBA, and for a DBA being interviewed by a company.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stacy Gray&lt;/strong&gt; gives you practical tips on preparation, getting the right mindset, handling questions you don&amp;rsquo;t know, and following up. She covers a lot in this quick post, making it &lt;a href="https://stacylaray.wordpress.com/2015/09/21/interviews/"&gt;a great fast review&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Taiob Ali&lt;/strong&gt; writes about a time when he &lt;a href="http://sqlworldwide.com/tsql-tuesday-93-do-not-drive-during-interview/"&gt;turned down a job offer due to the actions of the hiring manager&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tim Peters&lt;/strong&gt; explains why &lt;a href="https://tpet1433.wordpress.com/2017/08/08/tsql-tuesday-93-interviewing-patterns-anti-patterns/"&gt;saying, &amp;ldquo;It depends&amp;rdquo; is an interviewing anti-pattern&lt;/a&gt; &amp;ndash; and if you&amp;rsquo;re going to use &amp;ldquo;it depends&amp;rdquo; in an interview, how to go about it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Todd Kleinhans&lt;/strong&gt; &amp;ldquo;&lt;a href="https://toddkleinhans.wordpress.com/2017/08/08/i-dont-care-who-you-are/"&gt;doesn&amp;rsquo;t care who you are&lt;/a&gt;,&amp;rdquo; at least when it comes to an interview. And that&amp;rsquo;s a good thing.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sqlworkbooks-interview-parameter-sniffing.png"&gt;
&lt;/figure&gt;</description></item><item><title>Do Index Changes Remove Execution Plans from Cache?</title><link>https://kendralittle.com/2017/08/09/do-index-changes-remove-execution-plans-from-cache/</link><pubDate>Wed, 09 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/09/do-index-changes-remove-execution-plans-from-cache/</guid><description>&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/detective-dog-scoots-e1501178050465.png"&gt;
&lt;/figure&gt;
When you modify the indexes on a table, SQL Server needs to reconsider how it executes queries that reference that table. But the way this appears when you&amp;rsquo;re looking at your execution plan cache is far from obvious:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Impacted query plans are NOT removed from cache at the time you change an index. The next time the query is executed, it will be recompiled, and the new plan and related execution information will be placed in cache.&lt;/li&gt;
&lt;li&gt;This is true whether or not the index is used by the query.&lt;/li&gt;
&lt;li&gt;Even if the index is on columns in the table which are not referenced by the query, the query will recompile on the next run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To see this in action, you can play along with &lt;a href="https://gist.github.com/LitKnd/6707c691dc41b980025170f7b2c4869e"&gt;this sample script&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-drama-of-a-query-plan-and-changing-indexes"&gt;A drama of a query plan and changing indexes&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s how our story goes&amp;hellip;&lt;/p&gt;
&lt;h3 id="creating-an-index-doesnt-remove-a-plan-from-cache"&gt;Creating an index doesn&amp;rsquo;t remove a plan from cache&lt;/h3&gt;
&lt;p&gt;We run our Demo Query five times. Querying sys.dm_exec_query_stats and related DMVs, we see five executions, plan_generation_num = one.&lt;/p&gt;
&lt;p&gt;Then we create an index on a table referenced by the query.&lt;/p&gt;
&lt;p&gt;Querying the DMVs we still see five executions, plan_generation_num = one, and the query plan in cache. It hasn&amp;rsquo;t been removed!&lt;/p&gt;
&lt;h3 id="running-the-query-again-causes-a-recompile"&gt;Running the query again causes a recompile&lt;/h3&gt;
&lt;p&gt;We run our Demo Query again, this time four times.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: It&amp;rsquo;s important to highlight the query exactly, and not highlight spaces before the query on one run, and highlight differently the next run. Leading spaces are considered part of the query and inconsistent use of spaces impacts plan reuse.&lt;/p&gt;
&lt;p&gt;Querying the DMVs, we now see &lt;em&gt;four&lt;/em&gt; executions, and a new time for the plan creation_time. Plan_generation_num = two.&lt;/p&gt;
&lt;p&gt;If the index is relevant to the query and SQL Server decides to use it, we&amp;rsquo;ll see a new execution plan.&lt;/p&gt;
&lt;h3 id="an-index-rebuild-doesnt-remove-the-plan-from-cache-either"&gt;An index rebuild doesn&amp;rsquo;t remove the plan from cache, either&lt;/h3&gt;
&lt;p&gt;After running ALTER INDEX REBUILD, we still see four executions in the cache, and plan_generation_num=two.&lt;/p&gt;
&lt;p&gt;But if we rerun Demo Query three times, the first run triggers a recompile. We get a fresh creation_time for the plan, and now plan_generation_num has incremented to three.&lt;/p&gt;
&lt;h3 id="the-same-thing-holds-for-dropping-an-index"&gt;The same thing holds for dropping an index&lt;/h3&gt;
&lt;p&gt;This plays by the exact same rules. When you drop an index, it doesn&amp;rsquo;t remove the plan from the cache immediately.&lt;/p&gt;
&lt;p&gt;Put another way, you can have query plans in cache which refer to indexes that have been dropped, and do not currently exist. The query plan will be recompiled the next time the query is executed &amp;ndash; if it&amp;rsquo;s still in cache. (Maybe it could be removed in the meanwhile due to memory pressure, a restart, an administrator&amp;rsquo;s command, etc.)&lt;/p&gt;
&lt;h2 id="this-may-seem-weird-but-i-think-its-a-good-thing"&gt;This may seem weird, but I think it&amp;rsquo;s a good thing&lt;/h2&gt;
&lt;p&gt;I like this behavior in SQL Server. This means that if you run nightly index maintenance jobs which hit a lot of indexes with rebuilds, your execution plan cache isn&amp;rsquo;t largely cleared out. If you&amp;rsquo;re looking at sys.dm_exec_query_stats the next morning, you&amp;rsquo;re more likely to see relevant information.&lt;/p&gt;</description></item><item><title>The Story of an Interview Flop</title><link>https://kendralittle.com/2017/08/08/interview-patterns-anti-patterns-tsql-tuesday-93/</link><pubDate>Tue, 08 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/08/interview-patterns-anti-patterns-tsql-tuesday-93/</guid><description>&lt;p&gt;Some of the biggest lessons I&amp;rsquo;ve learned about interviewing come from an interview experience that meant a ton to me &amp;ndash; and all my dreams came crashing down.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tt_300_thumb_710BE775-150x150.jpg" width="230"&gt;
&lt;/figure&gt;
Welcome to &lt;a href="https://kendralittle.com/2017/08/01/tsql-tuesday-93-interviewing-patterns-anti-patterns/"&gt;T-SQL Tuesday #93&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;No time to watch?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scroll down, a transcript is below&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: Or listen on the go! This is available in podcast format &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/o-m7IJP_ZfQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="transcript-of-interview-patterns-and-anti-patterns-the-story-of-an-interview-flop"&gt;Transcript of &amp;ldquo;Interview Patterns and Anti-Patterns: The Story of an Interview Flop&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;I want to approach this topic with the story of my own experience of an interview that didn&amp;rsquo;t go well for me. It was an interview that was really, really important to me, and where I went through a lot of heartbreak and a lot of hurt feelings that it didn&amp;rsquo;t go well.&lt;/p&gt;
&lt;p&gt;Everything started out really promisingly enough.&lt;/p&gt;
&lt;p&gt;I was looking for jobs, and there was a job internally at the company I was working at &amp;ndash; and it sounded extremely exciting. Now, I didn&amp;rsquo;t know the folks in the team, but the manager looked at my background and said, &amp;ldquo;You know, you seem really interesting, I&amp;rsquo;d like to bring you in for an interview, even though it&amp;rsquo;s not an obvious fit.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I was REALLY excited. I went in for the interview, and I was super eager, ready to do my best, do everything I could. I had prepared as well as I was able to.&lt;/p&gt;
&lt;p&gt;The interview started, and there were lots of questions. I met with multiple people, and they were all very friendly, very hospitable, but they hit me with a series of technical questions, each in their own style. And I didn&amp;rsquo;t know the answer to a lot of these questions.&lt;/p&gt;
&lt;p&gt;But I did my best, and I worked to try to keep a confident, positive attitude. As the day went on, and I met with more and more interviewers, who had more and more questions, I realized &amp;ndash; OK, a lot of these times, I think I&amp;quot;m not even understanding the questions properly. I am so far out of the realm of this job and this team that I&amp;rsquo;m constantly trying to even clarify what we&amp;rsquo;re talking about and I don&amp;rsquo;t think that I&amp;rsquo;m getting it.&lt;/p&gt;
&lt;p&gt;Still, this job&amp;ndash; it seemed so cool and so perfect and just like the path that my career SHOULD take. It seemed like my destiny. I kept trying. Which is a good thing, I&amp;rsquo;m not sorry about that. I kept trying, I did my best and I said, &amp;ldquo;don&amp;rsquo;t let the problems get you down, keep going.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I met with yet another interviewer, who asked me questions that, this time I actually could understand. And they were questions like, &amp;ldquo;can you name some of the isolation levels in SQL Server?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I was embarrassed, because, you know, I knew about the &amp;lsquo;NOLOCK&amp;rsquo; keyword, I knew what Isolation Levels kind of were, but I quickly realized that even this &amp;ndash; which I knew enough to know was pretty foundational knowledge &amp;ndash; this was something that I didn&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;At this point in the day, things really started to sink in. Even though this job seemed like it really should be my destiny, to me, even though I really had my heart set on this, this just wasn&amp;rsquo;t a good fit.&lt;/p&gt;
&lt;p&gt;Sure enough, I wasn&amp;rsquo;t the only one who clued in on this. Things were handled very gracefully. This team was a wonderful team, you know, someone came to me after lunch and said, &amp;ldquo;you know, this just isn&amp;rsquo;t going to work out, we&amp;rsquo;re going to stop the interview loop here. Thanks for coming over, we really enjoyed meeting with you.&amp;rdquo; It was a very well-handled experience, because I really wasn&amp;rsquo;t the right fit for that job.&lt;/p&gt;
&lt;h3 id="i-took-this-really-hard"&gt;I took this really hard&lt;/h3&gt;
&lt;p&gt;I felt really, really bad afterwards. I felt very much like I had failed. I felt like I had failed myself, and even like I&amp;rsquo;d failed the person who took the chance on me and invited me over. I felt like I&amp;rsquo;d wasted everyone&amp;rsquo;s time.&lt;/p&gt;
&lt;p&gt;I took some time to lick my wounds. Over time it got better. Over a few days the experience didn&amp;rsquo;t feel quite so tough anymore. And I started feeling more and more like myself again. I was able to look back now at the interview and recognize &amp;ndash; I really wasn&amp;rsquo;t a good fit. Even though I had wanted that job so badly, it wasn&amp;rsquo;t the right place for me to go, there and then.&lt;/p&gt;
&lt;h3 id="eventually-i-woke-up-a-little"&gt;Eventually, I woke up a little&lt;/h3&gt;
&lt;p&gt;But, thinking about it, there were some things that had come up that day that were things I wanted to act on. Things like those questions about the isolation levels. I realized, you know, this IS something that I want to know, something that I want to learn about. And it&amp;rsquo;s not that I&amp;rsquo;m stupid. This is a piece of information I didn&amp;rsquo;t have because I had never encountered an opportunity that had prompted me to learn it.&lt;/p&gt;
&lt;p&gt;At the job I&amp;rsquo;d been working at, the isolation levels in use were well established. There weren&amp;rsquo;t a lot of questions about what the right isolation levels should be. None of my team really talked about this kind of thing very often. I realized that there might be cases when we would want to use a different isolation level, and there might be cases where I would see more potential ways we could improve things if I educated myself about this.&lt;/p&gt;
&lt;p&gt;So I set myself out a learning plan. I said, &amp;ldquo;I want to learn about this, this is something the interview brought up for me that I can act on.&amp;rdquo; I started doing research on this.&lt;/p&gt;
&lt;p&gt;I talked to members of my team as well. I realized that I&amp;rsquo;m not the only one who didn&amp;rsquo;t know this stuff. There are lots of people who haven&amp;rsquo;t encountered the right situation to learn about this.&lt;/p&gt;
&lt;h3 id="this-turned-into-something-amazing"&gt;This turned into something amazing&lt;/h3&gt;
&lt;p&gt;I was just starting to present on topics about SQL Server at this point. I&amp;rsquo;d been struggling to find the right topics to present on. And I realized &amp;ndash; this is actually a good topic! I&amp;rsquo;m learning about this, and I&amp;rsquo;ve progressed just past the beginner level. Giving a beginner&amp;rsquo;s introduction to this topic at free events like SQLSaturdays, that can help other people. And their questions can help me! When I give a presentation about what I&amp;rsquo;ve learned and people ask these, &amp;ldquo;Hey, &amp;lsquo;what if&amp;rsquo;&amp;rdquo; questions, those a great prompts for me. If I don&amp;rsquo;t know the answer yet, I can say, &amp;ldquo;Hey, I&amp;rsquo;ll look into that and I&amp;rsquo;ll write a blog post about that.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This is a great way for me to help other people learn this too. Because maybe they&amp;rsquo;re going to hit this in an interview situation. Maybe they&amp;rsquo;re going to hit situations at work where the information is gonna be helpful to them to solve problems.&lt;/p&gt;
&lt;p&gt;I found that I was able to help other people. And I was able to help myself, too. The more I learned about this topic, I did find cases where I was able to solve problems, and avoid CAUSING problems with my now improved knowledge of isolation levels.&lt;/p&gt;
&lt;p&gt;My speaking career grew, and I found that I really loved it. In many ways, that interview that at the time felt like SUCH a terrible failure of myself &amp;ndash; it was the beginning of one of my favorite topics and presentations that I ever did. And it really helped change my career trajectory. Just not in the way that I had originally anticipated at all.&lt;/p&gt;
&lt;h3 id="what-this-taught-me-about-interview-patterns-and-anti-patterns"&gt;What this taught me about interview patterns and anti-patterns&lt;/h3&gt;
&lt;p&gt;I think this is at the heart of interviewing. The patterns and the anti-patterns.&lt;/p&gt;
&lt;p&gt;It is valuable to recognize when it&amp;rsquo;s not a good fit. Whether you&amp;rsquo;re the candidate or not. Maybe you&amp;rsquo;re the interviewer. Recognizing when it&amp;rsquo;s not the right person for the right job, it doesn&amp;rsquo;t mean it&amp;rsquo;s the fault of the job, it doesn&amp;rsquo;t mean it&amp;rsquo;s the fault of the candidate. It really just means, this particular interview isn&amp;rsquo;t going to lead to a job match.&lt;/p&gt;
&lt;p&gt;But maybe, this person would be good in another part of the organization. Maybe there&amp;rsquo;s something to be gained from the relationships of the people who meet during the interview. Maybe there&amp;rsquo;s not. But recognizing when it&amp;rsquo;s not a good fit and accepting that WITHOUT blame is important.&lt;/p&gt;
&lt;p&gt;The proactive pattern there is, &amp;ldquo;OK you know sometimes we just have to accept it&amp;rsquo;s just not going to work out.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The anti-pattern, and the thing I would do differently if I had to go back and do it again, is &amp;ndash; I would try to, in that period after the interview, when I felt so badly about myself, I would try to take some time to reflect on it and give myself a little perspective sooner.&lt;/p&gt;
&lt;p&gt;When I heard that voice in my head saying, &amp;ldquo;You&amp;rsquo;re so dumb, it&amp;rsquo;s all your fault,&amp;rdquo; I would challenge that thought. I would say, &amp;ldquo;OK, you&amp;rsquo;re feeling bad that it didn&amp;rsquo;t go well because you had these hopes, but you just lack knowledge on these areas. Yeah, you&amp;rsquo;re not going to get the job, but, this doesn&amp;rsquo;t mean you&amp;rsquo;re dumb. This doesn&amp;rsquo;t mean it&amp;rsquo;s your fault. It&amp;rsquo;s not anyone else&amp;rsquo;s fault either, it just didn&amp;rsquo;t work out.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This is, I think, the hardest part of interviewing. It&amp;rsquo;s like dating, it&amp;rsquo;s very easy to feel rejected.&lt;/p&gt;
&lt;p&gt;But when you have those thoughts and feelings, challenge them. Really, it&amp;rsquo;s more about finding the right thing at the right time. There is a large element of luck, and background, and having the right skills for the right job at the right time.&lt;/p&gt;
&lt;p&gt;Other patterns: after an interview, no matter how well or poorly it goes, analyze the gaps, especially when you&amp;rsquo;re the candidate. What did you not know about? What do you wish you&amp;rsquo;d done differently?&lt;/p&gt;
&lt;p&gt;When it might be a match, sending a follow up email or or a follow up call or asking for a follow up meeting and saying, &amp;ldquo;you know, I was asked about X, and I really thought about it a lot and here&amp;rsquo;s what I learned and what I think afterwards. I think this is a really interesting topic.&amp;rdquo; Also, reaching out and making sure to thank people for their time &amp;ndash; follow up is really important.&lt;/p&gt;
&lt;p&gt;But thinking through those gaps, and letting the hiring team know that you&amp;rsquo;ve thought about it and are continuing to learn from the interview process can be really helpful if you&amp;rsquo;re close to being a good fit for the job.&lt;/p&gt;
&lt;p&gt;In my case, I wasn&amp;rsquo;t even close to being a good fit for the job. It was clear it wasn&amp;rsquo;t going to work out. But even then, looking at the gap there and saying, &amp;ldquo;what would I like to learn from this?&amp;rdquo; and, &amp;ldquo;How would I like to close the gap in some of these areas?&amp;rdquo; is really helpful.&lt;/p&gt;
&lt;h3 id="you-dont-have-to-close-every-gap"&gt;You don&amp;rsquo;t have to close every gap&lt;/h3&gt;
&lt;p&gt;In some interviews, you&amp;rsquo;re going to look at the gap analysis and you&amp;rsquo;re going to say, &amp;ldquo;OK there are things that I didn&amp;rsquo;t know but, that&amp;rsquo;s just not my path. That&amp;rsquo;s just not my career.&amp;rdquo; You don&amp;rsquo;t have to follow up on them all. But a lot of times there really are going to be things where you say &amp;ndash; and maybe they&amp;rsquo;re small, maybe they&amp;rsquo;re big &amp;ndash; things where you say, &amp;ldquo;hey, I do want to learn about this. And I do want to go out and change that.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Also, the other thing that I did, that I&amp;rsquo;m really proud of is that I kept trying. Not every interview I had after this was a success. Oh, absolutely NOT.&lt;/p&gt;
&lt;h3 id="interviewing-is-about-learning-and-persistence"&gt;Interviewing is about learning and persistence&lt;/h3&gt;
&lt;p&gt;But I did keep trying, not only in developing my speaking career, and learning to expand and change the ideas of what I could do with my life, but also just at looking around and being creative about things I could do. Trying different things. That persistence is your number one skill that will help you learn to enjoy interviewing rather than dread it.&lt;/p&gt;
&lt;p&gt;See interviews as an opportunity to learn. Whether you&amp;rsquo;re the candidate or whether you&amp;rsquo;re the interviewer, there is always something in an interview that you can learn from. Just understand that it may not be what you expected to learn.&lt;/p&gt;
&lt;h2 id="want-to-write-for-tsql-tuesday"&gt;Want to Write for TSQL Tuesday?&lt;/h2&gt;
&lt;p&gt;Learn &lt;a href="https://kendralittle.com/2017/08/01/tsql-tuesday-93-interviewing-patterns-anti-patterns/"&gt;how to join in here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Running SQL Server in a Docker Container on a Mac</title><link>https://kendralittle.com/2017/08/02/running-sql-server-in-a-docker-container-on-a-mac/</link><pubDate>Wed, 02 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/02/running-sql-server-in-a-docker-container-on-a-mac/</guid><description>&lt;p&gt;A user recently asked me what a good use case might be to run SQL Server on Linux in a Docker container.&lt;/p&gt;
&lt;p&gt;I recently got started with SQL Server in Docker on my Mac, and I&amp;rsquo;m really excited about the potential.&lt;/p&gt;
&lt;p&gt;Learn why and see how easy it is to rebuild your SQL Server on Docker once you have things configured in this 7 minute video:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Kd8SZsiuGIE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;In this video:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:10 - The use case I&amp;rsquo;m most excited about&lt;/li&gt;
&lt;li&gt;02:20 - Deleting all my Docker containers&lt;/li&gt;
&lt;li&gt;03:15 - Pulling the latest docker image for microsoft/mssql-server-linux&lt;/li&gt;
&lt;li&gt;04:15 - Using docker run to set up my container&lt;/li&gt;
&lt;li&gt;04:50 - Connecting to the docker container from SSMS installed in a VM running Windows&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-set-up-your-mac-the-first-time"&gt;How to set up your Mac the first time&lt;/h2&gt;
&lt;p&gt;I got everything going on my Mac using Aaron Bertrand&amp;rsquo;s great article, &lt;a href="https://blogs.sentryone.com/aaronbertrand/vs-code-mac-sql-linux-docker/"&gt;VS Code on Mac meets SQL Server on Linux (in Docker)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Setup took me around an hour (with lots of breaks), and the only halfway tricky part was figuring out what IP address to connect to, since I have a different networking setup than Aaron does.&lt;/p&gt;
&lt;h2 id="what-if-i-dont-want-to-delete-all-my-data"&gt;What if I don&amp;rsquo;t want to delete all my data?&lt;/h2&gt;
&lt;p&gt;In the video, I show clearing all your docker containers and grabbing fresh info. It&amp;rsquo;s definitely not a refined approach. If you&amp;rsquo;d like to be more civilized and update existing Docker containers, &lt;a href="https://facility9.com/2017/01/how-do-i-update-my-sql-server-docker-container/"&gt;Jeremiah Peschka wrote about how to do that&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-if-i-want-to-run-sql-server-in-linux-in-a-docker-container-on-windows"&gt;What if I want to run SQL Server in Linux in a Docker Container on Windows?&lt;/h2&gt;
&lt;p&gt;Start with &lt;a href="https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker"&gt;the Microsoft Quickstart guide&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>TSQL Tuesday #93: Interviewing Patterns &amp; Anti-Patterns</title><link>https://kendralittle.com/2017/08/01/tsql-tuesday-93-interviewing-patterns-anti-patterns/</link><pubDate>Tue, 01 Aug 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/08/01/tsql-tuesday-93-interviewing-patterns-anti-patterns/</guid><description>&lt;p&gt;Welcome to T-SQL Tuesday for August 2017!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://tsqltuesday.com/"&gt;T-SQL Tuesday&lt;/a&gt; is a chance for you to join in the SQL Server community and write a blog post on a suggested topic. You can use this as a way to start a new blog, dust off a blog you haven&amp;rsquo;t used in a while, or make it part of regular blogging: your choice!&lt;/p&gt;
&lt;p&gt;I would love for you to participate. The whole SQL Server community would. Please, join us!&lt;/p&gt;
&lt;p&gt;To participate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a post on the topic below&lt;/li&gt;
&lt;li&gt;Schedule the post to go live on Tuesday, August 8 (between zero am and midnight, UTC)&lt;/li&gt;
&lt;li&gt;Include the &lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2010/06/01/t-sql-tuesday-007-and-t-sql-tuesday-has-a-logo.aspx"&gt;TSQL Tuesday logo&lt;/a&gt; in the top of your post&lt;/li&gt;
&lt;li&gt;Link the post back to this one (it&amp;rsquo;s easier if you comment on this post and link it)&lt;/li&gt;
&lt;li&gt;Optional: Tweet a link to your post using the &lt;a href="https://twitter.com/hashtag/TSQL2sday?src=hash"&gt;#tsql2sday hash tag on Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Raccoon-e1501609718712.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Extra credit: if you&amp;rsquo;d like to host your own TSQL Tuesday in the future, &lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2017/01/03/t-sql-tuesday-rules-of-engagement.aspx"&gt;read the full rules for info on how to sign up.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I will write a round-up post on Monday, August 14 summarizing up all the magic you guys write.&lt;/p&gt;
&lt;h2 id="this-months-topic-interviewing-patterns-and-anti-patterns"&gt;This month&amp;rsquo;s topic: Interviewing Patterns and Anti-Patterns&lt;/h2&gt;
&lt;p&gt;What advice do you have for people preparing for or going through an interview?&lt;/p&gt;
&lt;p&gt;Feel free to be creative on this topic. Take whichever approach you like best:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may focus on patterns to follow for success&lt;/li&gt;
&lt;li&gt;You may list anti-patterns, too: things that might seem like a good idea, but are a recipe for disaster&lt;/li&gt;
&lt;li&gt;You can write about your own highs and lows as a candidate or as an interviewer&lt;/li&gt;
&lt;li&gt;Be as specific as you want for interviewing for or hiring for your given skillset, whether you&amp;rsquo;re a developer, DBA, manager, consultant, or something else entirely&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whichever route you take, it&amp;rsquo;s probably a good idea to disguise the identities of past employers, candidates, etc.&lt;/p&gt;
&lt;p&gt;Personally, I&amp;rsquo;m going to take the approach of writing about an interview for a SQL Server position that I &lt;em&gt;completely bombed&lt;/em&gt; as a candidate, and why it ended up being one of the best learning experiences of my life (although it was painful at the time). It taught me a lot about successful interviewing patterns.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t wait to learn about YOUR interviewing patterns and anti-patterns as well.&lt;/p&gt;
&lt;p&gt;Get ready, get set, get blogging!&lt;/p&gt;</description></item><item><title>The COMPRESS() TSQL Function in SQL Server 2016+</title><link>https://kendralittle.com/2017/07/31/the-compress-tsql-function-in-sql-server-2016/</link><pubDate>Mon, 31 Jul 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/07/31/the-compress-tsql-function-in-sql-server-2016/</guid><description>&lt;p&gt;One cool little feature in SQL Server 2016 is COMPRESS(). It&amp;rsquo;s a TSQL function available in all editions that shrinks down data using the GZIP algorithm (&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/compress-transact-sql"&gt;documentation&lt;/a&gt;).&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/badger-compressed-e1501522596773.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Things to know about COMPRESS():&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compressed data is in the VARBINARY(max) data type&lt;/li&gt;
&lt;li&gt;You get the data &amp;ldquo;back to normal&amp;rdquo; by  using the DECOMPRESS function - which also outputs VARBINARY(max)&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t use columns of the VARBINARY(max) type in an index key column&amp;ndash; but it may be useful to use the column as a filter in a filtered index, in some cases&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lets-play-with-an-example"&gt;Let&amp;rsquo;s play with an example&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to play with all the code, &lt;a href="https://gist.github.com/LitKnd/7350376ff3ace1dce62c7bbb4b92fd0f"&gt;grab it from this gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that we have a table with a &amp;lsquo;Notes&amp;rsquo; style field. For most rows, &amp;lsquo;Notes&amp;rsquo; is null. For the rows where it has data, sometimes it&amp;rsquo;s short, but sometimes it&amp;rsquo;s a super long set of characters.&lt;/p&gt;
&lt;p&gt;My first step is to create two tables with 10 million rows each with a &amp;lsquo;Notes&amp;rsquo; column. &amp;lsquo;Notes&amp;rsquo; is null for most rows &amp;mdash; but for 10K rows, it has varchar data in it ranging from 3 bytes to 29KB.&lt;/p&gt;
&lt;h2 id="how-much-compression-do-i-get"&gt;How much compression do I get?&lt;/h2&gt;
&lt;p&gt;I generated &amp;lsquo;Notes&amp;rsquo; data that compresses &lt;em&gt;very&lt;/em&gt; well - I just used a repeating set of characters. The table has just one other column, so most of the size is in the &amp;lsquo;Notes&amp;rsquo; column, so this results in a much smaller table.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/compress-function-tables.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;In the original table, the long character rows couldn&amp;rsquo;t fit on the in-row 8KB pages, so most of the &amp;lsquo;Notes&amp;rsquo; column had to be stored on LOB pages (for the rows where it&amp;rsquo;s not null). My super-compressible rows are so small that they don&amp;rsquo;t have to go off-row: not only is my table much smaller, it doesn&amp;rsquo;t even have to use LOB pages.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: I used the default setting where &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-tableoption-transact-sql"&gt;large value types may be stored in-row&lt;/a&gt; when I created the tables.
&lt;/div&gt;
&lt;h2 id="datatype-matters---a-lot"&gt;Datatype matters - a lot&lt;/h2&gt;
&lt;p&gt;If you use COMPRESS(), you need to make sure you remember the data type that you used before compressing the data. You can get the data back with the DECOMPRESS() function, but to read it properly you have to convert it back into the original type.&lt;/p&gt;
&lt;p&gt;In this case, I compressed VARCHAR data. Here&amp;rsquo;s what it looks like reading the data with just plain DECOMPRESS(), and DECOMPRESS() converted to VARCHAR and NVARCHAR.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/decompress-type-matters.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="you-have-limited-indexing-options---but-more-than-you-might-think"&gt;You have limited indexing options - but more than you might think&lt;/h2&gt;
&lt;p&gt;In the documentation on COMPRESS(), it says, &amp;ldquo;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/compress-transact-sql#remarks"&gt;Compressed data cannot be indexed&lt;/a&gt;.&amp;rdquo; That&amp;rsquo;s not 100% true, at least not according to my understanding of the word &amp;ldquo;indexed&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It is true that COMPRESS() outputs a VARBINARY(max) column. This data type can&amp;rsquo;t be a key column in an index.&lt;/p&gt;
&lt;p&gt;However, columns with this data type &lt;em&gt;can&lt;/em&gt; be used in the filter of a filtered index in a way that may be interesting for cases like our &amp;lsquo;Notes&amp;rsquo; column, where most of the rows have a NULL value for &amp;lsquo;Notes&amp;rsquo; and the column is highly selective.&lt;/p&gt;
&lt;p&gt;In this case, we might want to create a covering filtered index, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_filtertest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compressed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CompressedId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Notes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Notes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using Notes as an included column does store another copy of it. But in the case of our &amp;lsquo;Notes&amp;rsquo; column, the compressed column is all in-row data and is not particularly large.&lt;/p&gt;
&lt;p&gt;To get SQL Server to use this index, we may have to write our queries carefully, though. Just using the &amp;lsquo;Notes&amp;rsquo; column in a predicate doesn&amp;rsquo;t do it:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/no-notes.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Instead, we have to explicitly add a predicate to our query that matches the IS NOT NULL filter:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/notes-predicate-matches.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;So it may be possible in some cases to use indexes with data generated with COMPRESS(), depending on what you want to do.&lt;/p&gt;</description></item><item><title>Desktop Wallpapers and Webcasts on Isolation Levels and Memory</title><link>https://kendralittle.com/2017/07/28/desktop-wallpapers-and-webcasts-on-isolation-levels-and-memory/</link><pubDate>Fri, 28 Jul 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/07/28/desktop-wallpapers-and-webcasts-on-isolation-levels-and-memory/</guid><description>&lt;p&gt;I&amp;rsquo;ve been having lots of fun drawing and doing webcasts this summer. I&amp;rsquo;ve got four SQL Server themed desktop wallpapers to share, and I&amp;rsquo;ve got lots more coming&amp;ndash; along with a new chunk of free webcasts.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/detective-dog-scoots-e1501178050465.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="sql-server-desktop-wallpapers"&gt;SQL Server desktop wallpapers&lt;/h2&gt;
&lt;p&gt;I have four wallpapers available for free:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top Queries in SQL Server&lt;/li&gt;
&lt;li&gt;SSMS Shortcuts &amp;amp; Secrets&lt;/li&gt;
&lt;li&gt;Partitioning Jargon&lt;/li&gt;
&lt;li&gt;The Case of the Slow Temp Table Update (featuring Detective Scoots)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Find them &lt;a href="https://github.com/LitKnd/littlekendracomments/tree/main/SQLWorkbooks-Wallpaper-and-Posters"&gt;on GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I would love it if you shared the downloads with others. The very nicest way to share is to share the URL (instead of just sending the files).&lt;/p&gt;
&lt;h2 id="more-webcasts"&gt;More webcasts!&lt;/h2&gt;
&lt;p&gt;My weekly webcast is a big highlight of my week. I really love the great questions and comments I get: that helps a ton when figuring out how to turn this content into online courses. I&amp;rsquo;ve scheduled a bunch of new webcasts through October. Here are the topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aug 10 – SQL Server Practice Interview: Performance Tuning&lt;/li&gt;
&lt;li&gt;Aug 17 – Choosing the Best Key for a Nonclustered Index&lt;/li&gt;
&lt;li&gt;Aug 24 – Keys vs Includes in Nonclustered Indexes&lt;/li&gt;
&lt;li&gt;Aug 31 – Why Indexed Views Cause Glory or Grief&lt;/li&gt;
&lt;li&gt;Sep 21 – Read Committed is Bonkers&lt;/li&gt;
&lt;li&gt;Sep 28 – Filtered Indexes: Fantastic or Frustrating?&lt;/li&gt;
&lt;li&gt;Oct 5 – RCSI and Snapshot Isolation in SQL Server&lt;/li&gt;
&lt;li&gt;Oct 19 – Pressure Testing Memory Configuration&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Downloadable SQL Server Desktop Wallpapers</title><link>https://kendralittle.com/2017/07/26/downloadable-sql-server-desktop-wallpapers/</link><pubDate>Wed, 26 Jul 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/07/26/downloadable-sql-server-desktop-wallpapers/</guid><description>&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Desktop-Wallpapers.jpg"&gt;
&lt;/figure&gt;
I&amp;rsquo;ve set things up so you can quickly download desktop wallpapers featuring cartoons and SQL Server concepts.&lt;/p&gt;
&lt;h2 id="get-em-here"&gt;Get &amp;rsquo;em here&lt;/h2&gt;
&lt;p&gt;Grab wallpapers at &lt;a href="https://github.com/LitKnd/littlekendracomments/tree/main/SQLWorkbooks-Wallpaper-and-Posters"&gt;https://github.com/LitKnd/littlekendracomments/tree/main/SQLWorkbooks-Wallpaper-and-Posters&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Did that Query Eliminate Partitions? (videos)</title><link>https://kendralittle.com/2017/07/19/did-that-query-eliminate-partitions-videos/</link><pubDate>Wed, 19 Jul 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/07/19/did-that-query-eliminate-partitions-videos/</guid><description>&lt;p&gt;Table partitioning makes execution plans a bit more confusing.&lt;/p&gt;
&lt;h2 id="free-course"&gt;Free Course&lt;/h2&gt;
&lt;p&gt;I have &lt;a href="https://kendralittle.com/course/the-weird-wonderful-world-of-execution-plans-partitioned-tables-columnstore-indexes/"&gt;a free online course&lt;/a&gt; which walks you through decoding execution plans, including whether or not partition elimination occurred.&lt;/p&gt;</description></item><item><title>IF Statement Branching and Parameter Sniffing</title><link>https://kendralittle.com/2017/07/12/if-statement-branching-and-parameter-sniffing/</link><pubDate>Wed, 12 Jul 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/07/12/if-statement-branching-and-parameter-sniffing/</guid><description>&lt;p&gt;It can be tricky to remember that SQL Server doesn&amp;rsquo;t short circuit on IF statements in stored procedures. Even when you know this, sometimes it&amp;rsquo;s hard to recognize the impacts.&lt;/p&gt;
&lt;h2 id="heres-an-example"&gt;Here&amp;rsquo;s an example&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/review-flags-procedure.jpg" width="600"&gt;
&lt;/figure&gt;
&lt;h3 id="first-the-parameter-is-sniffed"&gt;First, the parameter is sniffed&amp;hellip;&lt;/h3&gt;
&lt;p&gt;The first time that dbo.ReviewFlags is executed after the database comes online, it&amp;rsquo;s with an invalid parameter, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is caught by the IF block, hits the RAISERROR, and goes down to the THROW block, and the output is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 50000, Level 11, State 1, Procedure ReviewFlags, Line 8 [Batch Start Line 70]
@Flag must be a value between 1 and 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But even though SQL Server didn&amp;rsquo;t execute the SELECT statement, it still compiled it. And it also cached the plan.&lt;/p&gt;
&lt;h3 id="then-the-sniffed-plan-is-re-used"&gt;Then, the &amp;ldquo;sniffed&amp;rdquo; plan is re-used&lt;/h3&gt;
&lt;p&gt;When we run the procedure again with a valid value for @Flag&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get a very undersized execution plan for @Flag = 1. The row estimate is super low.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/undersized-plan.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;We can confirm that this plan was optimized for @Flag = null by looking at the properties of the SELECT operator in the actual plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/parameter-compiled-value.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;We compiled for @Flag = NULL, even though this statement can never execute with that value for @Flag&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="wed-get-a-different-plan-if-we-optimize-for-flag--1"&gt;We&amp;rsquo;d get a different plan if we optimize for @Flag = 1&lt;/h3&gt;
&lt;p&gt;For testing purposes, I can execute the procedure WITH RECOMPILE to tell SQL Server to not re-use the plan, and compile this fresh for me. (I only use this for testing, and note that if you have nested procedures or dynamic SQL, it will re-use sub-plans.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This time I get a better plan, optimized for @Flag = 1&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/a-different-plan.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="how-to-work-around-this"&gt;How to work around this?&lt;/h2&gt;
&lt;p&gt;Realistically, the first thing to consider is how likely the procedure is to be run with invalid values. If this procedure is typically executed from an application with a drop-down that doesn&amp;rsquo;t contain the invalid values and RAISERROR is unlikely to catch an unloved parameter value, you probably don&amp;rsquo;t care much (unless you work for NASA).&lt;/p&gt;
&lt;p&gt;If you do want to make sure that the SELECT statement is optimized only when it&amp;rsquo;s executed, there are a variety of options, with different pros and cons.&lt;/p&gt;
&lt;p&gt;You could use OPTION RECOMPILE on the statement, but the trade-off is extra CPU and a more difficult time monitoring performance with the execution plan cache long term.&lt;/p&gt;
&lt;p&gt;Personally, I would usually rather do a different solution.&lt;/p&gt;
&lt;h3 id="mmmm-dynamic-sql"&gt;mmmm, Dynamic SQL&lt;/h3&gt;
&lt;p&gt;One option is a dynamic SQL style solution that allows plan re-use, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TINYINT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XACT_ABORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RAISERROR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@Flag must be a value between 1 and 5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; SELECT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; fnbd.FirstNameId,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; fn.FirstName,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; fnbd.Gender
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; FROM agg.FirstNameByYearState as fnbd
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; JOIN ref.FirstName as fn on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; fnbd.FirstNameId = fn.FirstNameId
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; WHERE fnbd.Flag = @Flag&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@Flag TINYINT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="o"&gt;=@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CATCH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;THROW&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CATCH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parameterized dynamic SQL still allows &amp;ldquo;healthy&amp;rdquo; (hopefully) parameter sniffing on the value passed in for @Flag, but that statement will only compile the first time that sp_executesql is actually &lt;em&gt;executed&lt;/em&gt;. Therefore it will only &amp;ldquo;sniff&amp;rdquo; allowed parameters.&lt;/p&gt;
&lt;p&gt;Similar to this, you could use a separate stored procedure for the SELECT statement.&lt;/p&gt;
&lt;h3 id="forcible-sniffing-with-optimize-for"&gt;Forcible sniffing with OPTIMIZE FOR&lt;/h3&gt;
&lt;p&gt;Another option is to direct SQL Server what value to &amp;ldquo;sniff&amp;rdquo;. A perma-sniff, if you will. We can do this with an &amp;ldquo;optimize for&amp;rdquo; hint:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReviewFlags&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TINYINT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XACT_ABORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RAISERROR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@Flag must be a value between 1 and 5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByYearState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPTIMIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CATCH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;THROW&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CATCH&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="remember-ifs-dont-prevent-sniffs"&gt;Remember: &amp;ldquo;IFs don&amp;rsquo;t prevent sniffs&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;But if you say that out loud, people are probably going to look at you funny.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/LitKnd/d888c5324d0a2de7c2f50ffe96f2e9e8"&gt;Full demo code for this example is in this gist&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Index Rebuild, Reorganize, and Statistics in Maintenance Plans in SQL Server 2016</title><link>https://kendralittle.com/2017/07/05/index-rebuild-reorganize-and-statistics-in-maintenance-plans-in-sql-server-2016/</link><pubDate>Wed, 05 Jul 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/07/05/index-rebuild-reorganize-and-statistics-in-maintenance-plans-in-sql-server-2016/</guid><description>&lt;p&gt;Working with maintenance plans is supposed to be easy, but I find it to be quite difficult.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Index-SQL-Server-Feline-Method.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;In part, this is because they can often be buggy. To write this post today, I had to go back and install SSMS 16.5, because I wasn&amp;rsquo;t able to configure logging or change some aspects about my test maintenance plan in SSMS 17. (I use case sensitive instances, and &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/3133065"&gt;this bug&lt;/a&gt; also impacts things like the maintenance plan log dialog box.)&lt;/p&gt;
&lt;p&gt;And in part this is because the documentation for maintenance plans doesn&amp;rsquo;t tend to be as clear as the documentation for TSQL commands. So in the interest of saving other folks time, I wanted to share what I learned about the Rebuild Index Task, Reorganize Index Task, and Update Statistics Task in SQL Server 2016.&lt;/p&gt;
&lt;h2 id="you-dont-have-to-use-maintenance-plans-but-lots-of-people-still-do"&gt;You don&amp;rsquo;t have to use maintenance plans, but lots of people still do&lt;/h2&gt;
&lt;p&gt;If you already are happily doing your index and statistics maintenance with &lt;a href="https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html"&gt;Ola Hallengren&amp;rsquo;s free scripts&lt;/a&gt;, &lt;a href="http://minionware.net/reindex/"&gt;Minion Reindex&lt;/a&gt;, or a different solution that works well for you - I&amp;rsquo;m not writing this post to change your mind! Not at all. &lt;em&gt;Go forth and be happy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using maintenance plans because you&amp;rsquo;re not comfortable with other scripts, or your management has a mandate that you only use the built-in tools, then this post is for you.&lt;/p&gt;
&lt;p&gt;And just to be clear, I am writing this post to give you reasons to &lt;em&gt;not&lt;/em&gt; use maintenance plans, and to go try out one of those scripts. I&amp;rsquo;m going to step through the improvements added into maintenance plans in SQL Server 2016, and explain why they still have notable flaws.&lt;/p&gt;
&lt;p&gt;To be honest, I don&amp;rsquo;t blame Microsoft for those flaws: there are such great scripts for this generated by the community that I don&amp;rsquo;t know why they&amp;rsquo;d put much effort into making index and statistics maintenance perfect in the product. I wouldn&amp;rsquo;t! If customers want something more flexible, there are multiple free options out there which are highly configurable. Personally, I&amp;rsquo;m happier if Microsoft&amp;rsquo;s developer time goes into more cool features inside the products where community scripts can&amp;rsquo;t help out.&lt;/p&gt;
&lt;p&gt;So please don&amp;rsquo;t read this post as complaints about the product! Really, I just want to encourage you to use cool community scripts.&lt;/p&gt;
&lt;h2 id="the-index-maintenance-tasks-are-historically-very-inefficient-in-sql-server"&gt;The index maintenance tasks are historically &lt;em&gt;very&lt;/em&gt; inefficient in SQL Server&lt;/h2&gt;
&lt;p&gt;For older versions of SQL Server (the ones most people use still, since most folks are slow to upgrade), maintenance plans offer a &amp;ldquo;defragment everything, every time&amp;rdquo; approach to index maintenance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Reorganize Index task reorganizes all indexes, regardless of fragmentation level&lt;/li&gt;
&lt;li&gt;The Rebuild Index task similarly bulldozes through everything and rebuilds every index, without checking fragmentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s not a lot of guidance in the maintenance plan designer, so it&amp;rsquo;s not uncommon for people to rebuild every index, and then reorganize it afterwards: defragment one way, then defragment another.&lt;/p&gt;
&lt;p&gt;Although this is a lot of wasted effort, if you have small databases and a large maintenance window, it may not be a big problem.&lt;/p&gt;
&lt;p&gt;But the bigger your data gets, the longer it takes. And more and more often, people like to be able to work nights and weekends, and they expect performance from the database whenever they happen to be active. That maintenance window is shrinking.&lt;/p&gt;
&lt;h2 id="sql-server-2016-added-some-features-to-the-rebuild-index-task"&gt;SQL Server 2016 added some features to the Rebuild Index Task&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve had a very handy dynamic management view in SQL Server to check for fragmentation since SQL Server 2005, but maintenance plans didn&amp;rsquo;t give you a built-in way to use it until SQL Server 2016. Better late than never, maybe?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the updated Index Rebuild task. New stuff is highlighted in yellow:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/rebuild-index-task-sql-server-2016.jpg"&gt;
&lt;/figure&gt;
&lt;h3 id="things-that-are-better-for-index-rebuild-for-enterprise-edition-maxdop-low-priority"&gt;Things that are better for Index Rebuild for Enterprise Edition: Maxdop, Low Priority&lt;/h3&gt;
&lt;p&gt;You can now configure MAXDOP for index rebuilds in a maintenance plan. This feature has existed since SQL Server 2005, but you had to use TSQL to specify it before. Using more than one core for index rebuild operations is an Enterprise feature. This will work in Enterprise Edition and Developer Edition, but you&amp;rsquo;re only going to get single threaded rebuilds in Standard Edition.&lt;/p&gt;
&lt;p&gt;You can also configure online index rebuilds to wait at low priority. This feature was added in SQL Server 2014, and it&amp;rsquo;s specific to the Enterprise Online Rebuild option. It can reduce blocking chains for the locks needed for the index maintenance, and it now gives you options about what you&amp;rsquo;d like to happen after waiting (just like the TSQL).&lt;/p&gt;
&lt;h3 id="things-that-are-better-for-all-editions-fragmentation-level-and-page-count"&gt;Things that are better for all editions: Fragmentation Level and Page Count&lt;/h3&gt;
&lt;p&gt;The ability to skip indexes that are tiny, or which aren&amp;rsquo;t very fragmented is a big improvement, and brings this task into the modern world. Partly. (More on that below.)&lt;/p&gt;
&lt;h3 id="things-that-confused-me-index-stats-options---scan-type"&gt;Things that confused me: Index Stats Options - Scan type&lt;/h3&gt;
&lt;p&gt;I had a serious case of Wishful Thinking (TM) when it came to the bottom part of this dialog box.&lt;/p&gt;
&lt;p&gt;The problem was the phrase &amp;lsquo;index stats options&amp;rsquo;. I was SURE that the word &amp;lsquo;stats&amp;rsquo; here was related to the statistics in SQL Server that describe the data distribution in columns or indexes, that are used by the optimizer when generating execution plans. I thought that a feature had been added to this task where it might update index or column statistics if the index wasn&amp;rsquo;t fragmented enough to qualify for a rebuild (something that the more sophisticated free scripts above do).  I was thinking that &amp;lsquo;Sampled&amp;rsquo; was a dynamic sample, and &amp;lsquo;Detailed&amp;rsquo; was perhaps FULLSCAN.&lt;/p&gt;
&lt;p&gt;Nope. Nope. Nope.  After much confusion, I realized that in fact this has &lt;em&gt;nothing&lt;/em&gt; to do with those stats.&lt;/p&gt;
&lt;p&gt;Instead, this part of the dialog lets you control how the task checks the level of fragmentation in the index from &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-index-physical-stats-transact-sql#scanning-modes"&gt;the sys.dm_db_index_physical_stats DMV&lt;/a&gt;: Fast = &amp;lsquo;LIMITED&amp;rsquo;, Sampled = &amp;lsquo;SAMPLED&amp;rsquo;, &amp;lsquo;Detailed&amp;rsquo;=&amp;lsquo;DETAILED&amp;rsquo;. (I did some tracing to confirm the mapping.)&lt;/p&gt;
&lt;p&gt;It is kinda nice that 2016 now lets you configure this, although generally you just want to use &amp;lsquo;LIMITED&amp;rsquo;, aka &amp;lsquo;Fast&amp;rsquo;. This is the default, and it&amp;rsquo;s what most free scripts out there do.&lt;/p&gt;
&lt;h2 id="the-reorganize-index-task-got-a-little-makeover-in-2016-too"&gt;The Reorganize Index Task got a little makeover in 2016, too&lt;/h2&gt;
&lt;p&gt;Here is the task, with the new options highlighted:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/reorganize-index-task-sql-server-2016.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Reorganize is always single threaded and online, in every edition, so we don&amp;rsquo;t have options for that. But we can now skip small indexes, skip indexes that aren&amp;rsquo;t very fragmented, and control the level of thoroughness of the scan in sys.dm_db_index_physical_stats.&lt;/p&gt;
&lt;h2 id="what-problems-do-maintenance-plans-still-have-for-index-and-statistics-maintenance-in-2016"&gt;What problems do maintenance plans still have for index and statistics maintenance in 2016?&lt;/h2&gt;
&lt;p&gt;Maintenance plans still have a few problems when it comes to index and stats maintenance, and the more data you have, the more they&amp;rsquo;ll hurt.&lt;/p&gt;
&lt;h3 id="1-youll-probably-end-up-sampling-the-same-objects-for-fragmentation-more-than-once"&gt;1) You&amp;rsquo;ll probably end up sampling the same objects for fragmentation more than once&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say that I configure my maintenance plan like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/rebuild-then-reorganize.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Disclaimer: This is a totally simplified maintenance plan and it doesn&amp;rsquo;t clean up any of its mess at all. I&amp;rsquo;m showing this to talk about the problems it has and to try to help you justify using a different solution, not to show you best practices with it :)[/caption]&lt;/p&gt;
&lt;p&gt;I configure it conservatively, to save effort:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The rebuild task only rebuilds indexes over 50% fragmented which can be rebuilt online&lt;/li&gt;
&lt;li&gt;The reorganize task only reorganizes indexes over 25% fragmented&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What if the rebuild index task finds a 20GB index that&amp;rsquo;s 60% fragmented and rebuilds it?&lt;/p&gt;
&lt;p&gt;Well, when reorganize comes along, it will see that the 20GB index isn&amp;rsquo;t fragmented &amp;ndash; but it still has to take the time to sample it all over again to see that, because these are separate tasks. (I did some tracing to confirm that each task scans the fragmentation individually, and they do.)&lt;/p&gt;
&lt;p&gt;In contrast, a clever script will step through the indexes, skip low page counts based on metadata, sample fragmentation &lt;em&gt;once&lt;/em&gt;, and then decide whether to rebuild or reorganize.&lt;/p&gt;
&lt;h3 id="2-these-tasks-dont-do-anything-new-for-index-and-column-statistics-theother-kind-of-stats"&gt;2) These tasks don&amp;rsquo;t do anything new for index and column statistics (the &lt;em&gt;other&lt;/em&gt; kind of stats)&lt;/h3&gt;
&lt;p&gt;When it comes to performance, maintaining index and column statistics often makes more of a difference than defragmenting your indexes.&lt;/p&gt;
&lt;p&gt;Sure, you need to address index fragmentation sometimes. If you never defragment your indexes, you&amp;rsquo;ll end up with tons of trapped empty space and bloated indexes - and that wastes space not only on disk, but also in memory.&lt;/p&gt;
&lt;p&gt;But for many databases, updating index and column statistics &amp;ndash; the little objects that help SQL Server estimate how much data there is &amp;ndash; can make a major difference to performance, and it&amp;rsquo;s helpful to update them on a regular basis.&lt;/p&gt;
&lt;p&gt;Generally, you want to integrate statistics maintenance with index maintenance, if you&amp;rsquo;re running both, because rebuilding an index automatically gives it nice fresh statistics (equivalent to updating them with fullscan).&lt;/p&gt;
&lt;p&gt;But maintenance plans don&amp;rsquo;t have a feature to be smart about these stats.&lt;/p&gt;
&lt;h3 id="3-the-update-statistics-task-is-waaaaay-nastier-than-it-looks-at-first"&gt;3) The Update Statistics task is waaaaay nastier than it looks at first&lt;/h3&gt;
&lt;p&gt;One of my least favorite things about maintenance plans is this task, because SQL Server is &lt;em&gt;so much smarter than this!&lt;/em&gt; This task is really outdated and very problematic, but you&amp;rsquo;d never know until it burns you. Here it is with the default values selected:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-statistics-task.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Problems with this task:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It bulldozes through all your statistics, whether or not they have had any modifications since they were last updated. If you have the &amp;ldquo;auto-create statistics&amp;rdquo; setting enabled (it&amp;rsquo;s on by default, and it&amp;rsquo;s a very good thing), you may have tons and tons of little column statistics. The statistics are a good thing: blindly updating them all isn&amp;rsquo;t.&lt;/li&gt;
&lt;li&gt;It defaults to FULLSCAN. &lt;a href="https://kendralittle.com/2017/06/how-much-longer-does-it-take-to-update-statistics-with-fullscan/"&gt;Updating statistics on a table with FULLSCAN will repeatedly scan the table and/or indexes on the table, and can take a very long time&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The only other option is a hardcoded sample. It defaults to 50 rows, but you could change it to a percentage. &lt;em&gt;This is a lousy choice.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More clever maintenance scripts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Skip statistics maintenance on an index that has been rebuilt (because it got a stats update with that operation)&lt;/li&gt;
&lt;li&gt;Checks other index-related statistics and column statistics to see if they&amp;rsquo;ve been modified, and skips them if they haven&amp;rsquo;t had any action&lt;/li&gt;
&lt;li&gt;Allows you to use the default dynamic sampling for statistics update. This dynamic sampling is built into the UPDATE STATISTICS command (the maintenance plan just doesn&amp;rsquo;t give an option for it). For small objects, it&amp;rsquo;ll decide to scan the whole thing. For larger objects it will take a sampling of rows.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="3b-this-means-that-the-imperfect-workaround-of-sp_updatestats-lives-on"&gt;3b) This means that the imperfect workaround of sp_updatestats lives on&lt;/h3&gt;
&lt;p&gt;Many folks get wise to the fact that the Update Statistics task isn&amp;rsquo;t their friend after they realize that it&amp;rsquo;s making their maintenance take forever. Often what they turn to instead is an &amp;lsquo;Execute TSQL Statement&amp;rsquo; task. They use it to execute some code calling the built-in procedure sp_updatestats for each database they care about.&lt;/p&gt;
&lt;p&gt;While sp_updatestats is definitely a bit smarter (it skips stats with not changes, and it uses the dynamic sampling), it has some flaws itself. &lt;a href="https://sqlperformance.com/2013/07/sql-statistics/statistics-updates"&gt;Erin Stellato summarizes the problems with sp_updatestats in this post&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="4-you-dont-get-configuration-options-for-partitioned-indexes"&gt;4) You don&amp;rsquo;t get configuration options for partitioned indexes&lt;/h3&gt;
&lt;p&gt;Feature recap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In SQL Server 2016 SP1, we got the ability to use table partitioning in Standard, Web, and Express Edition&lt;/li&gt;
&lt;li&gt;In SQL Server 2014, we got the ability to rebuild individual partitions online in Enterprise Edition. In Standard Edition, rebuild is offline, but you have the choice between doing individual partitions and the whole index.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But I don&amp;rsquo;t see &lt;em&gt;any&lt;/em&gt; options about partitioning in those Index Rebuild and Reorganize dialogue boxes, do you?&lt;/p&gt;
&lt;p&gt;So I did some basic testing. I pointed my maintenance plan at a partitioned table, and asked it to script out the TSQL it would use (this is an estimate, not a guarantee). Here&amp;rsquo;s an excerpt of what it gave me:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cx_pt_FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REBUILD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ONLINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WAIT_AT_LOW_PRIORITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_DURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MINUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ABORT_AFTER_WAIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cx_pt_FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REBUILD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ONLINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WAIT_AT_LOW_PRIORITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_DURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MINUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ABORT_AFTER_WAIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cx_pt_FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REBUILD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SORT_IN_TEMPDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ONLINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WAIT_AT_LOW_PRIORITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_DURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MINUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ABORT_AFTER_WAIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATA_COMPRESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So it appears that at least on SQL Server 2016 SP1, it defaults to partition level rebuilds, whether you ask for them or not. It also appears to check the fragmentation level for each partition, and skip those beneath the specified fragmentation level.&lt;/p&gt;
&lt;p&gt;If you want to skip any partitions all the time or rebuild some indexes entirely and not at the partition level, there&amp;rsquo;s no option for that.&lt;/p&gt;
&lt;h3 id="5-theres-no-good-options-for-exclusion"&gt;5) There&amp;rsquo;s no good options for exclusion&lt;/h3&gt;
&lt;p&gt;I may have some large objects in my database that I don&amp;rsquo;t want to regularly maintain. One common example are logging tables, where data may be frequently inserted, but they are queried only rarely, if internal staff need to investigate a problem. You may have some indexes on the tables to help with these queries, but you don&amp;rsquo;t care much about their performance.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t have a lot of time for maintenance, you probably want to skip these tables most of the time, and only do the barest of maintenance once a month, or possibly even less frequently. This can let you focus on the objects you care about in limited time.&lt;/p&gt;
&lt;p&gt;Maintenance plans don&amp;rsquo;t have a good way to do this. You can select specific objects, but not &lt;em&gt;exclude&lt;/em&gt; specific objects, and you have to configure it on every task. This can lead to inconsistencies, or to new objects not being picked up by the maintenance plans.&lt;/p&gt;
&lt;h2 id="what-to-do"&gt;What to do?&lt;/h2&gt;
&lt;p&gt;If you read all the way through this looooong post, I&amp;rsquo;m guessing that you&amp;rsquo;re not completely happy with your maintenance plan. You&amp;rsquo;d like to improve it.&lt;/p&gt;
&lt;p&gt;Good news! There are lots of great ways you can do that. The SQL Server community has lots of clever folks who built them and want to share them with you.&lt;/p&gt;
&lt;p&gt;Your best option is to look at the websites for &lt;a href="https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html"&gt;Ola Hallengren&amp;rsquo;s free scripts&lt;/a&gt; and &lt;a href="http://minionware.net/reindex/"&gt;Minion Reindex&lt;/a&gt;. Check out the documentation a little. Decide which you&amp;rsquo;d like to test out, and grab the code and put it on a test server. Make a change plan to replace your maintenance plans with one of those instead.&lt;/p&gt;
&lt;p&gt;What if you have a mandate from your management to use the built-in maintenance plans?&lt;/p&gt;
&lt;p&gt;This would be my question: is it OK for us to run custom code in maintenance plans? Like for that situation where the built-in Update Statistics command doesn&amp;rsquo;t work, is it OK for me to run a script that&amp;rsquo;s smarter about statistics maintenance?&lt;/p&gt;
&lt;p&gt;If there&amp;rsquo;s any leeway at all for that, then you&amp;rsquo;ve got a little bit of an open door to work with. You can start the process of getting external free scripts and their licenses reviewed.&lt;/p&gt;
&lt;p&gt;If there isn&amp;rsquo;t any leeway at all for that, then I would make the best of what I have, and keep an eye out for places where we have problems due to the limitations in maintenance plans. If you come across incidents where using an improved script might work, then you have a good opportunity to bring it up again in a friendly way.&lt;/p&gt;</description></item><item><title>New Free Webcasts on Interviewing and Indexing</title><link>https://kendralittle.com/2017/06/29/new-free-webcasts-on-interviewing-and-indexing/</link><pubDate>Thu, 29 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/29/new-free-webcasts-on-interviewing-and-indexing/</guid><description>&lt;p&gt;Sharpen your performance tuning and indexing skills this summer, &lt;em&gt;for free&lt;/em&gt;, one week at a time!&lt;/p&gt;
&lt;h2 id="upcoming-webcasts"&gt;Upcoming Webcasts&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve recently added five more free webcasts for summer to my lineup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thu, July 27, 9AM PST /12 PM EST - The Case of the Slow Temp Table&lt;/li&gt;
&lt;li&gt;Thu, Aug 10, 9AM PST /12 PM EST - SQL Server Practice Interview: Performance Tuning&lt;/li&gt;
&lt;li&gt;Thu, Aug 17, 9AM PST /12 PM EST - Choosing the Best Key for a Nonclustered Index&lt;/li&gt;
&lt;li&gt;Thu, Aug 24, 9AM PST /12 PM EST - Keys vs Includes in Nonclustered Indexes&lt;/li&gt;
&lt;li&gt;Thu, Aug 31, 9AM PST /12 PM EST - Why Indexed Views Cause Glory or Grief&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Registration has now closed.&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Using sp_WhoIsActive with Temp Tables to Limit Data Collected</title><link>https://kendralittle.com/2017/06/28/using-sp_whoisactive-with-temp-tables-to-limit-data-collected/</link><pubDate>Wed, 28 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/28/using-sp_whoisactive-with-temp-tables-to-limit-data-collected/</guid><description>&lt;p&gt;The &lt;a href="http://whoisactive.com/"&gt;free sp_WhoIsActive procedure&lt;/a&gt; by Adam Machanic can be very useful for monitoring SQL Server: I&amp;rsquo;m a big fan.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;ve learned the hard way that it&amp;rsquo;s easy to collect too much information with sp_WhoIsActive, particularly if you set up jobs where you have the procedure log data to a table for later review. Collecting the text of SQL Server queries, their execution plans, and more, can take up a lot of room, and I&amp;rsquo;ve managed to fill up a server drive or two with a little over-eager collection. Whoops!&lt;/p&gt;
&lt;p&gt;Sometimes it can be useful to store the results of sp_WhoIsActive in a temporary object, and review the contents before deciding whether or not to store the data permanently.&lt;/p&gt;
&lt;p&gt;Or alternately, you might want to do this to programmatically review the results of sp_WhoIsActive at the current moment to check whether you want to fire off an alert based on different criteria.&lt;/p&gt;
&lt;p&gt;Because of scoping issues, regular temp tables don&amp;rsquo;t really work well for this. But you can easily use either a global temporary table, or a short-lived table in a user database.&lt;/p&gt;
&lt;h2 id="an-example-sessions-with-tempdb_allocations--0"&gt;An example: sessions with tempdb_allocations &amp;gt; 0&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say I want to periodically sample how many tempdb_allocations are being used by different sessions, and collect the query text and query plan if they are available. I only want to keep data for sessions who have tempdb_allocations &amp;gt; 0 permanently.&lt;/p&gt;
&lt;p&gt;I could do something like this&amp;hellip;&lt;/p&gt;
&lt;h3 id="step-1-create-a-permanent-table-to-store-the-info-i-care-about"&gt;Step 1) Create a permanent table to store the info I care about&lt;/h3&gt;
&lt;p&gt;The first step is to create a regular database table named dbo.WhoIsActive_tempdb, where we&amp;rsquo;ll store data for review:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This assumes I have a database named dba where I can store monitoring info.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;The code in this post doesn&amp;#39;t delete or limit the data you put into this table, so make sure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;you either clean it out, have plenty space, or don&amp;#39;t insert enough to cause you problems */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dba&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WhoIsActive_tempdb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;output_column_list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[tempdb%][%]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_plans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;return_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;format_output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OUTPUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;table_name&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I used the @schema parameter to have sp_WhoIsActive generate the schema for the table itself. &lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2011/04/25/capturing-the-output-a-month-of-activity-monitoring-part-25-of-30.aspx"&gt;Full instructions on doing this by Adam are here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since I care about tempdb in the case of this example, I used @output_column_list to specify that those columns should come first, followed by the rest of the columns.&lt;/p&gt;
&lt;p&gt;I also elected to set @get_plans to 1 to get query execution plans if they&amp;rsquo;re available. That&amp;rsquo;s not free, and they can take up a lot of room, but they can contain a lot of helpful info.&lt;/p&gt;
&lt;h3 id="step-2-option-1-sample-sp_whoisactive-into-a-global-temp-table-then-insert-only-rows-we-care-about-into-the-permanent-table"&gt;Step 2, Option 1) Sample sp_WhoIsActive into a global temp table, then insert only rows we care about into the permanent table&lt;/h3&gt;
&lt;p&gt;If we only want to store rows where tempdb_allocations &amp;gt; 0 in the permanent table, then one way to do this is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a temporary table each time we run sp_WhoIsActive&lt;/li&gt;
&lt;li&gt;Insert the current sample into that table&lt;/li&gt;
&lt;li&gt;Insert the rows we want to keep permanently into the &amp;lsquo;real&amp;rsquo; table&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because of scoping reasons with dynamic SQL, this isn&amp;rsquo;t easy to do with a normal temporary table. One relatively easy workaround for that is to use a global temporary table. To reduce the possibility of name collisions (like if you have a job running this, and you accidentally run it yourself in a session at the same time), is to use a GUID in the name of the temporary table, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;##WhoIsActive_&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NEWID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;output_column_list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[tempdb%][%]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_plans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;return_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;format_output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OUTPUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;table_name&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;output_column_list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[tempdb%][%]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_plans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;format_output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;destination_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;INSERT dbo.WhoIsActive_tempdb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;SELECT *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;FROM &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;WHERE tempdb_allocations &amp;gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;OPTION (RECOMPILE);&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DROP TABLE &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, I&amp;rsquo;m running sp_WhoIsActive with the same options I used before. I first use @schema to create a global temporary table with a name like [##WhoIsActive_E91F175D-C09A-44E7-98E7-10A18E038873].&lt;/p&gt;
&lt;p&gt;I then select rows from the temp table who have tempdb_allocations &amp;gt; 0, and insert them into dbo.WhoIsActive_tempdb.&lt;/p&gt;
&lt;h2 id="but-what-if-we-want-to-use-less-tempdb"&gt;But&amp;hellip; what if we want to use less tempdb?&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s a great question.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that you&amp;rsquo;re firing this whole thing off at a time when tempdb is filling up fast, or maybe at a time when you might have allocation contention in tempdb. We can&amp;rsquo;t prevent our monitoring queries from using tempdb altogether, but maybe we don&amp;rsquo;t want to create temp tables.&lt;/p&gt;
&lt;p&gt;No problem. You can use slightly different code to store sp_WhoIsActive results in a short lived permanent table in the dba database.&lt;/p&gt;
&lt;h3 id="step-2-option-2-short-lived-permanent-table-in-a-user-database"&gt;Step 2, Option 2) Short lived permanent table in a user database&lt;/h3&gt;
&lt;p&gt;The only real difference in this code from the second sample above is the &amp;ldquo;use dba&amp;rdquo; statement, and a change in the name of @whoisactive_table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dba&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUOTENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WhoIsActive_&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NEWID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;output_column_list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[tempdb%][%]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_plans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;return_schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;format_output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OUTPUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;table_name&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_WhoIsActive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;output_column_list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[tempdb%][%]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;get_plans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;format_output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;destination_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;INSERT dbo.WhoIsActive_tempdb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;SELECT *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;FROM &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;WHERE tempdb_allocations &amp;gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;OPTION (RECOMPILE);&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_executesql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dsql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DROP TABLE &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;whoisactive_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When run this way, sp_WhoIsActive still allocates resources in tempdb (be aware that some of that overhead is just part of using a complex query like this), but the object creation is kept in the user database.&lt;/p&gt;
&lt;h2 id="sometimes-you-can-simply-use-a-filter-built-into-sp_whoisactive"&gt;Sometimes, you can simply use a filter built into sp_WhoIsActive!&lt;/h2&gt;
&lt;p&gt;Want to see data just for a single login, program name, database, host name, or session?&lt;/p&gt;
&lt;p&gt;Or just want to exclude something based on login, program name, database, host name, or session?&lt;/p&gt;
&lt;p&gt;In those case, you might simply use the @filter_type and @filter parameters on sp_WhoIsActive and save yourself some complexity. Here&amp;rsquo;s &lt;a href="http://sqlblog.com/blogs/adam_machanic/archive/2011/04/09/deciding-what-not-to-see-a-month-of-activity-monitoring-part-9-of-30.aspx"&gt;the documentation on how to do that&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy monitoring!&lt;/p&gt;</description></item><item><title>Join me for Why Did My Clever Index Change Backfire? at the 24 Hours of PASS</title><link>https://kendralittle.com/2017/06/23/join-me-for-why-did-my-clever-index-change-backfire-at-the-24-hours-of-pass/</link><pubDate>Fri, 23 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/23/join-me-for-why-did-my-clever-index-change-backfire-at-the-24-hours-of-pass/</guid><description>&lt;iframe src="//giphy.com/embed/4SYQ0rDfsBifu" width="480" height="270" frameborder="0"&gt;&lt;/iframe&gt;
&lt;p&gt;You&amp;rsquo;ve got a performance problem and you know just the cool index trick that will fix it!&lt;/p&gt;
&lt;p&gt;Until it goes utterly wrong.&lt;/p&gt;
&lt;p&gt;Join me for this free session in the 24 hours of PASS to see multiple quick demos of index changes that seem like a great idea&amp;hellip; until they either don&amp;rsquo;t work, or make things worse.&lt;/p&gt;
&lt;h2 id="how-to-sign-up"&gt;How to sign up&lt;/h2&gt;
&lt;p&gt;My session is on Wed, July 19, 9 am Pacific / 12 pm Eastern / 4pm UTC.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pass.org/24hours/2017/summitpreview/Registration.aspx"&gt;Register for this free event here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;BYO dog!&lt;/p&gt;
&lt;iframe src="//giphy.com/embed/mokQK7oyiR8Sk" width="480" height="371" frameborder="0"&gt;&lt;/iframe&gt;</description></item><item><title>How to Enable the Debug Channel in Extended Events for the Query Thread Profile XEvent in SQL Sever 2014+</title><link>https://kendralittle.com/2017/06/19/how-to-enabletrace-the-query-thread-profile-extended-event-in-sql-sever-2014/</link><pubDate>Mon, 19 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/19/how-to-enabletrace-the-query-thread-profile-extended-event-in-sql-sever-2014/</guid><description>&lt;p&gt;Microsoft recently gave us a more lightweight way to trace data related to execution plan performance. As of SQL Server 2014 SP2, you can trace the query_thread_profile Extended Event.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/new-session-1-300x145.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="but-why-doesnt-it-show-up-in-the-extended-events-wizard"&gt;But why doesn&amp;rsquo;t it show up in the Extended Events Wizard?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m a pretty lazy person, and for simple traces I typically just right click on the &amp;ldquo;Sessions&amp;rdquo; bucket under extended events and use &amp;ldquo;New Session&amp;rdquo;, then step through the GUI.&lt;/p&gt;
&lt;p&gt;But when you step through this and go to add the query_thread_profile event, it&amp;rsquo;s&amp;hellip; missing!?!?!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/such_empty-1024x300.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="theres-a-secret-dropdown-called-channel"&gt;There&amp;rsquo;s a secret dropdown, called &amp;ldquo;Channel&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;This was really hard for me to see. So hard that I looked at another explanation for it online, and completely missed what they&amp;rsquo;re talking about.&lt;/p&gt;
&lt;p&gt;The word &amp;ldquo;Channel&amp;rdquo; is a dropdown. I thought that little carrot mark was for sorting events by type&amp;mdash; and I had _no idea t_hat it contained entire categories of Extended Events that don&amp;rsquo;t show by default! Among those are the &amp;ldquo;Debug&amp;rdquo; events. Here&amp;rsquo;s the secret dropdown, highlighted in yellow&amp;hellip;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/enable-the-debug-channel-extended-events-1024x715.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="once-you-check-off-debug-the-event-shows-up"&gt;Once you check off &amp;ldquo;Debug&amp;rdquo;, the event shows up&lt;/h2&gt;
&lt;p&gt;Whew! Now you can add the event, configure your trace, and test out the feature very easily.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/there-it-si-1024x378.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;ve been using Extended Events for a while. I like them, but I find the GUI very non-intuitive. (Obviously.) In the past, I&amp;rsquo;ve had a few cases where I couldn&amp;rsquo;t figure out how to add an event without just scraping together the TSQL for it&amp;ndash; and now I think I know why I couldn&amp;rsquo;t find it!&lt;/p&gt;</description></item><item><title>How Much Longer Does it Take To Update Statistics with FULLSCAN?</title><link>https://kendralittle.com/2017/06/14/how-much-longer-does-it-take-to-update-statistics-with-fullscan/</link><pubDate>Wed, 14 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/14/how-much-longer-does-it-take-to-update-statistics-with-fullscan/</guid><description>&lt;p&gt;When I was recently working on the course, &amp;ldquo;Should Developers Manage Index Maintenance?&amp;rdquo; I explained that in my experience, statistics maintenance can make more of a difference to performance than index maintenance can.&lt;/p&gt;
&lt;p&gt;I also noted that one of the big &amp;ldquo;maintenance goofs&amp;rdquo; that I&amp;rsquo;ve made in the past is to be overly eager to update statistics. And to update them with FULLSCAN.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s some detail on why doing that can be so slow, and how it can eat up more resources than you might think. (This is a long one, so scroll on down to the end of the post for a list of spoilers, if you like.)&lt;/p&gt;
&lt;h2 id="when-you-update-statistics-against-a-table-sql-server-may-have-to-scan-the-table-many-many-times"&gt;When you update statistics against a table, SQL Server may have to scan the table many, many times&lt;/h2&gt;
&lt;p&gt;When people manually update statistics, they generally don&amp;rsquo;t update just a single column stats, or stats for a single index. They identify a table that&amp;rsquo;s a problem, and create a command to update stats against the whole table.&lt;/p&gt;
&lt;p&gt;The command to update statistics against an entire table looks something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATISTICS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But then, if they&amp;rsquo;ve gone to this trouble, they think, &amp;ldquo;I should try to make the updated statistics as accurate as possible!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The obvious way to do that it to tell SQL Server to do more than just take a sample of the data: instead to do it with FULLSCAN.&lt;/p&gt;
&lt;p&gt;So they use a command like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;STATISTICS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FULLSCAN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="how-much-longer-does-fullscan-take"&gt;How much longer does FULLSCAN take?&lt;/h2&gt;
&lt;p&gt;On my test instance, the command that uses the default sampling takes 6 seconds to complete.&lt;/p&gt;
&lt;p&gt;The command which adds &amp;ldquo;WITH FULLSCAN&amp;rdquo; takes just over &lt;em&gt;five minutes&lt;/em&gt; to complete.&lt;/p&gt;
&lt;p&gt;The reason is that those two little words can add a &lt;em&gt;whole lot&lt;/em&gt; of extra IO to the work of updating statistics.&lt;/p&gt;
&lt;h2 id="what-is-update-statisticsreally-doing"&gt;What is update statistics really doing?&lt;/h2&gt;
&lt;p&gt;My table is pretty narrow. It has only six statistics on it: I queried information about them &lt;a href="https://kendralittle.com/2016/12/06/when-did-sql-server-last-update-that-statistic-how-much-has-been-modified-since-and-what-columns-are-in-the-stat/"&gt;with a query like this&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/table-stats.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The three statistics with the funny names beginning in _WA_Sys are column statistics that SQL Server automatically created when I ran queries with joins or where clauses using those columns. The other three statistics were automatically created when I created indexes.&lt;/p&gt;
&lt;p&gt;I ran a trace when I updated statistics with FULLSCAN, and here&amp;rsquo;s what I saw, stat by stat&amp;hellip;&lt;/p&gt;
&lt;h3 id="1-fakebirthdatestamp-and-firstnamebybirthdateid-cx_firstnamebybirthdate_1966_2015"&gt;1) FakeBirthDateStamp and FirstNameByBirthDateId (cx_FirstNameByBirthDate_1966_2015)&lt;/h3&gt;
&lt;p&gt;The clustered index has a two-column statistic. Those two columns match up with this query in the trace:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatMan&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PERCENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READUNCOMMITTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_MS_UPDSTATS_TBL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAXDOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the plan I saw in the trace:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-stats-fullscan-plan-0.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;There are only two columns output from the clustered index scan: FirstNameByBirthDateId and FakeBirthDateStamp, the two columns needed to update the stat.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: this plan does seem a bit odd to me, as it could have found these columns in a non-clustered index: these are the key columns in the clustered index, which will be present in each nonclustered index, whether we ask for it or not. But it chose to use the clustered index.
&lt;/div&gt;
&lt;h3 id="2-fakebirthdatestamp-column-stat-_wa_sys_00000001_4db4832c"&gt;2) FakeBirthDateStamp column stat (_WA_Sys_00000001_4DB4832C)&lt;/h3&gt;
&lt;p&gt;Next, SQL Server went to work on the FakeBirthDateStamp column statistic.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;But wait!&amp;rdquo; you might think. &amp;ldquo;We just got that info when updating the stat for the clustered index!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Yes, we did. But we&amp;rsquo;re going to go scan something else, anyway, because that&amp;rsquo;s how we roll. &lt;em&gt;We need to independently collect data for each&lt;/em&gt; &lt;em&gt;statistic, even though you ran the command against the whole table&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the query that SQL Server runs next, which lines up with the column stat:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatMan&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PERCENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READUNCOMMITTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_MS_UPDSTATS_TBL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAXDOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here is the plan it used to get the data to update the column statistic:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-stats-fullscan-plan-1.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;This time, SQL Server chose to scan the nonclustered index on FirstNameId. Looking at the properties of the scan, it figured out that FakeBirthDateStamp would be there (because of the clustering key), and decided to scan this nonclustered index and output just that column:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/output-list.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;But &amp;hellip; oops! We didn&amp;rsquo;t allocate enough memory for our sort and had a little spill in tempdb.&lt;/p&gt;
&lt;h3 id="3-birthyear-_wa_sys_00000003_4db4832c"&gt;3) BirthYear (_WA_Sys_00000003_4DB4832C)&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re still reading, here&amp;rsquo;s where things get crazier than I expected.&lt;/p&gt;
&lt;p&gt;BirthYear is a computed column. SQL Server uses the following query to gather data to update my column statistic&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatMan&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PERCENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READUNCOMMITTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_MS_UPDSTATS_TBL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAXDOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s the plan I got:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-stats-fullscan-plan-birthyear.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s the play by play of what that plan is doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scan the nonclustered index on FirstNameId, and output the &amp;ldquo;secret&amp;rdquo; FakeBirthDateStamp column (which is there because it&amp;rsquo;s part of the clustered index)&lt;/li&gt;
&lt;li&gt;Use compute scalar operators to apply the formula for the BirthYear column and compute it for every row&lt;/li&gt;
&lt;li&gt;Then we have our tempdb spill again&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Computed columns can have statistics on them. That&amp;rsquo;s a good thing. I don&amp;rsquo;t have a non-clustered index on this column for SQL Server to scan, but I was surprised that it wanted to re-compute every single row for it, because I &lt;em&gt;did&lt;/em&gt; mark this column as &amp;lsquo;persisted&amp;rsquo; (&lt;a href="https://gist.github.com/LitKnd/fa902f27e3214d739df428477ba23d3f"&gt;I double-checked with a query&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;But this time, SQL Server really didn&amp;rsquo;t want to scan that clustered index again (we just did it, after all), so it decided to recompute every. Single. Row.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re not done yet, though. We&amp;rsquo;re only halfway through the statistic!&lt;/p&gt;
&lt;h3 id="4-firstnameid-ix_firstnamebybirthdate_1966_2015_firstnameid"&gt;4) FirstNameId (ix_FirstNameByBirthDate_1966_2015_FirstNameId)&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve scanned every row in the nonclustered index on FirstNameId twice already. But we haven&amp;rsquo;t actually updated its statistic yet, so&amp;hellip; you guessed it, let&amp;rsquo;s scan it again!&lt;/p&gt;
&lt;p&gt;The query to gather data to update this stat is&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatMan&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PERCENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READUNCOMMITTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_MS_UPDSTATS_TBL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAXDOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the plan was&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-stats-fullscan-plan-firstnameid.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Look on the bright side: it may be the third time we&amp;rsquo;ve scanned this nonclustered index, but at least this time we didn&amp;rsquo;t have any tempdb spills.&lt;/p&gt;
&lt;h3 id="5-statecode-gender-ix_firstnamebybirthdate_1966_2015_statecode_gender_includes"&gt;5) StateCode, Gender (ix_FirstNameByBirthDate_1966_2015_StateCode_Gender_INCLUDES)&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve got another nonclustered index, and it has two key columns. Those two columns are in the auto-generated index statistic. To gather information for them, SQL Server runs this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatMan&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PERCENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READUNCOMMITTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_MS_UPDSTATS_TBL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAXDOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gets a plan that scans the associated nonclustered index:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-stats-fullscan-plan-statecode-gender.jpg"&gt;
&lt;/figure&gt;
&lt;h3 id="6-gender-_wa_sys_00000006_4db4832c"&gt;6) Gender (_WA_Sys_00000006_4DB4832C)&lt;/h3&gt;
&lt;p&gt;Whew, I&amp;rsquo;m glad this is a narrow table. We have a column statistic on Gender. This might look like a duplicate stat to the index statistic &amp;mdash; but note that the index statistic leads on StateCode. That turns out to make it quite different (because only the leading column in a statistic gets information in the histogram). So the column statistic on Gender only is really quite different.&lt;/p&gt;
&lt;p&gt;Again, SQL Server can&amp;rsquo;t re-use any of the information it previously scanned. It runs this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatMan&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PERCENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;READUNCOMMITTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SC0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_MS_UPDSTATS_TBL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAXDOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which gets this execution plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/update-stats-fullscan-plan-gender.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Confession: this execution plan makes me a little sad. I knew I wasn&amp;rsquo;t going to get a &lt;em&gt;happy&lt;/em&gt; ending for this post, but I was really rooting for it to at least scan the nonclustered index on StateCode and Gender (which is physically much smaller).&lt;/p&gt;
&lt;p&gt;Nope. It decided to scan the whole clustered index, again, this time to output the Gender column. And it spilled 97K pages in tempdb.&lt;/p&gt;
&lt;h2 id="what-i-usedto-see-this-info"&gt;What I used to see this info&lt;/h2&gt;
&lt;p&gt;I set up a quick and sloppy extended events trace to get the following events:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;query_post_execution_showplan - this impacts performance when you collect it, so I also updated statistics without the trace running to measure basic timing&lt;/li&gt;
&lt;li&gt;sp_statement_completed - this shows you information for each &amp;ldquo;SELECT StatMan&amp;rdquo; statement run behind the scenes&lt;/li&gt;
&lt;li&gt;sql_statement_completed - this gives you overall information for the whole &amp;lsquo;UPDATE STATISTICS dbo.FirstNameByBirthDate_1966_2015 WITH FULLSCAN;&amp;rsquo; when it finishes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The query execution plan screenshots are from the free SentryOne Plan Explorer, taken with Snagit.&lt;/p&gt;
&lt;h2 id="summing-up-and-takeaways"&gt;Summing up and takeaways&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what you need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you must manually update statistics, stick with the default sampling (unless you have a great reason to do otherwise)&lt;/li&gt;
&lt;li&gt;If you must manually update statistics, update a specific column or index stat only (unless you have a great reason to do otherwise)&lt;/li&gt;
&lt;li&gt;If you can come up with a better way to get stabile high performance, such as tuning queries or indexes, it removes this headache&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For every statistic you update (even as part of a command to update statistics on a whole table), SQL Server has to do a separate read operation&lt;/li&gt;
&lt;li&gt;When you use FULLSCAN, this means scanning a table or an index&lt;/li&gt;
&lt;li&gt;SQL Server may choose to recompute all the values in a computed column, even if it&amp;rsquo;s persisted, when you update that column statistic with FULLSCAN&lt;/li&gt;
&lt;li&gt;SQL Server may not always choose to scan a nonclustered index instead of the clustered index, even when that seems like a viable option&lt;/li&gt;
&lt;li&gt;Updating statistics can generate activity you might not expect, like spills in tempdb, if it underestimates how many resources it will need for things like SORT operators in the plan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Who knew that so much weirdness could come from such a simple command?!?!?&lt;/p&gt;</description></item><item><title>When does a Snapshot Transaction Really Begin?</title><link>https://kendralittle.com/2017/06/12/when-does-a-snapshot-transaction-really-begin/</link><pubDate>Mon, 12 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/12/when-does-a-snapshot-transaction-really-begin/</guid><description>&lt;p&gt;They say, &amp;ldquo;never read the comments&amp;rdquo; on the internet, but I&amp;rsquo;m lucky to get lots of interesting points and questions in my comments.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/snapshot.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Recently, &lt;a href="https://kendralittle.com/2016/02/18/how-to-choose-rcsi-snapshot-isolation-levels/"&gt;Jim mentioned&lt;/a&gt; that he was doing some testing in a database that allows snapshot isolation level, and he saw the something like the following sequence of events. (These are fake timestamps, just for the purpose of illustration.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00.000 - Session A sets its isolation level to snapshot&lt;/li&gt;
&lt;li&gt;00.001 - Session A explicitly begins a transaction with BEGIN TRAN&lt;/li&gt;
&lt;li&gt;00.002 - Session A starts a WAITFOR command for 15 seconds&lt;/li&gt;
&lt;li&gt;10.000 - Before the WAITFOR completes, Session B inserts rows into dbo.Table&lt;/li&gt;
&lt;li&gt;15.001 - Session A starts a SELECT from dbo.Table, which returns the rows that Session B inserted&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This seems wrong, because many of us commonly say things like, &amp;ldquo;in Snapshot Isolation level, all statements see data consistent with the beginning of the transaction.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But in this case, Session B inserted the rows &lt;em&gt;after&lt;/em&gt; Session A began its transaction using Snapshot Isolation level. So why did Session A see those rows?&lt;/p&gt;
&lt;h2 id="snapshot-transactions-dont-start-with-begin-tran"&gt;Snapshot transactions don&amp;rsquo;t start with BEGIN TRAN&lt;/h2&gt;
&lt;p&gt;I hadn&amp;rsquo;t really thought much about this before Jim&amp;rsquo;s comment. But this behavior is documented deep within the whitepaper, &lt;a href="https://technet.microsoft.com/en-us/library/ms345124%28v=sql.90%29.aspx"&gt;SQL Server 2005 Row Versioning-Based Transaction Isolation&lt;/a&gt;. There&amp;rsquo;s a paragraph titled &amp;lsquo;Understanding the &amp;ldquo;Beginning&amp;rdquo; of a Transaction&amp;rsquo; which explains:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;hellip;the version that a transaction will use is based on the first statement that accesses data, and not the BEGIN TRAN that creates the transaction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To make this even clearer, the version the transaction will used is based on the first statement that accesses data &lt;em&gt;using SNAPSHOT ISOLATION.&lt;/em&gt; If you hint the first statement in the transaction to lower the isolation level (with a NOLOCK hint, for example), it doesn&amp;rsquo;t read versioned data or &amp;lsquo;set&amp;rsquo; the version for the transaction.&lt;/p&gt;
&lt;p&gt;So perhaps I should change my language a bit, and start saying something more like, &amp;ldquo;Under snapshot isolation, all statements see data consistent with the first time data is accessed within the transaction.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;For most users, this won&amp;rsquo;t make a difference, as usually we perform data access immediately after starting a transaction.&lt;/p&gt;
&lt;p&gt;But oftentimes folks do need to get a bit creative, so making this explicit is worthwhile.&lt;/p&gt;</description></item><item><title>When does physical reads include read-ahead reads in SQL Server?</title><link>https://kendralittle.com/2017/06/07/does-physical-reads-include-read-ahead-reads-in-sql-server/</link><pubDate>Wed, 07 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/07/does-physical-reads-include-read-ahead-reads-in-sql-server/</guid><description>&lt;p&gt;SQL Server has more than one way to pull pages in from disk for your queries. SQL Server can do a physical read of an 8KB page, or an extent of 8  of those 8KB pages.&lt;/p&gt;
&lt;p&gt;SQL Server can also use the &amp;ldquo;read-ahead&amp;rdquo; mechanism to pull even larger chunks of data in from disk when you have a query that wants to read a lot of data &amp;ndash; because just plucking one 8KB page or even 64KB of pages into disk isn&amp;rsquo;t super fast when you need lotsa pages.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/pre-fetching.png" width="230"&gt;
&lt;/figure&gt;
But these terms get a little confusing when you&amp;rsquo;re changing between different diagnostic tools in SQL Server, because some of these tools include read-ahead reads in physical reads, and some don&amp;rsquo;t!&lt;/p&gt;
&lt;p&gt;I took my &lt;a href="https://kendralittle.com/2017/05/24/when-a-nonclustered-index-and-statistics-make-a-query-slower/"&gt;simple test query from this prior post&lt;/a&gt; out for a drive, and measured its physical reads and read-ahead reads in a few different ways. Here&amp;rsquo;s what I found.&lt;/p&gt;
&lt;h2 id="statistics-io-output-separates-physical-and-read-ahead-reads"&gt;STATISTICS IO output separates physical and read-ahead reads&lt;/h2&gt;
&lt;p&gt;SQL Server will return information about how many reads you did to your session&amp;rsquo;s Messages tab when you run &amp;ldquo;&lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/statements/set-statistics-io-transact-sql"&gt;SET STATISTICS IO ON&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what it says for our query:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;(2 row(s) affected)
Table &amp;#39;Worktable&amp;#39;. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table &amp;#39;Workfile&amp;#39;. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table &amp;#39;FirstNameByBirthDate\_1966\_2015&amp;#39;. Scan count 1, logical reads 7758553, physical reads 5625, read-ahead reads 438117, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table &amp;#39;FirstName&amp;#39;. Scan count 1, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this case, physical reads = 5,625 and read-ahead reads = 438,117 against our largest table. There are 2 other reads against the small FirstName table for a total of 443,384 physical pages read.&lt;/p&gt;
&lt;h2 id="the-sysdm_exec_query_stats-dmv-combines-all-physical-reads"&gt;The sys.dm_exec_query_stats DMV combines all physical reads&lt;/h2&gt;
&lt;p&gt;When I query the sys.dm_exec_query_stats DMV and pull back execution statistics just for my query (with &lt;a href="https://gist.github.com/LitKnd/3a7ba99c88ba07d3f64f4d0bade71d79"&gt;a diagnostic query like this&lt;/a&gt;), it doesn&amp;rsquo;t have a separate column for read-ahead reads. Instead, it reports all reads from disk under physical reads:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sys_dm_exec_query_stats_physical_reads.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Notably, this DMV shows that more physical reads were done than were reported by STATISTICS IO! It saw 483,128 physical reads.&lt;/p&gt;
&lt;h2 id="extended-events-trace-on-sql_statement_completed-also-combines-physical-reads"&gt;Extended Events trace on sql_statement_completed also combines physical reads&lt;/h2&gt;
&lt;p&gt;Well, how about a trace? I ran a quick trace on my session and collected sql_statement_completed. Like sys.dm_exec_query_stats, it doesn&amp;rsquo;t separate out read-ahead reads: it reports everything as physical reads.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/extended-events-sql-statement-completed_logical_and_physical_reads.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;I was really happy to see that the trace agreed with the DMV, and that they both saw 483,128 physical reads. It&amp;rsquo;s nice to have a &lt;em&gt;little&lt;/em&gt; consistency!&lt;/p&gt;
&lt;h2 id="what-about-tracingsqlserverfile_read_completed-for-read-ahead-reads"&gt;What about tracing sqlserver.file_read_completed for read-ahead reads?&lt;/h2&gt;
&lt;p&gt;As &lt;a href="https://blogs.msdn.microsoft.com/sql_pfe_blog/2013/03/14/dissecting-sql-server-physical-reads-with-extended-events-and-process-monitor/"&gt;Tim Chapman wrote over on the SQL PFE blog&lt;/a&gt;, the sqlserver.file_read_completed extended event lets you see the number of reads from disk and the size of physical reads done.&lt;/p&gt;
&lt;p&gt;So I set up my Extended Events trace, cleared out my buffer pool, and ran my query. Here&amp;rsquo;s the physical read count and sizes, I saw, with some columns added for analysis:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/extended-events-file_read_completed-e1495733197714.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The &amp;ldquo;read-ahead reads&amp;rdquo; column here has been converted to the page count read. I didn&amp;rsquo;t include single page reads  or the reads of a single extent in that column. (I also was a little lazy and didn&amp;rsquo;t bother to filter out &amp;ldquo;cache warming&amp;rdquo; pages read, which is probably around 9 pages, but &lt;em&gt;don&amp;rsquo;t tell anyone, OK?&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;This trace saw fewer read-ahead reads than STATISTICS IO reported. It also saw fewer physical reads than sys.dm_exec_query_stats or sql_statement_completed saw. But we&amp;rsquo;re in the ballpark, and these are different methods of measurement.&lt;/p&gt;
&lt;h2 id="my-view-statistics-io-isnt-super-precise-but-it-is-cool-that-it-separates-out-read-ahead-reads"&gt;My view: STATISTICS IO isn&amp;rsquo;t super-precise, but it is cool that it separates out read-ahead reads&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s actually not easy to see how many read-ahead reads your query is doing! STATISTICS IO is one of the few places that breaks it out in a way that&amp;rsquo;s simple to see. I see these numbers as a ballpark estimate, and I wouldn&amp;rsquo;t bet on them being &amp;ldquo;exactly right&amp;rdquo;. They&amp;rsquo;re good enough to be really useful.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re looking at sys.dm_exec_query_stats, or you&amp;rsquo;re tracing statements completed, in those places &amp;ldquo;physical reads&amp;rdquo; includes reads of all sizes&amp;ndash; including read-ahead reads.&lt;/p&gt;</description></item><item><title>Top 5 Misleading SQL Server Performance Counters</title><link>https://kendralittle.com/2017/06/05/top-5-misleading-sql-server-performance-counters/</link><pubDate>Mon, 05 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/05/top-5-misleading-sql-server-performance-counters/</guid><description>&lt;p&gt;Perfmon counters are an excellent tool for monitoring and sometimes troubleshooting Microsoft SQL Server. But some counters can get you into trouble, because they don&amp;rsquo;t mean what many people think. Learn what to look out for in the world of widely-used perfmon counters.&lt;/p&gt;
&lt;h2 id="sqlserver-buffer-managerbuffer-cache-hit-ratio"&gt;SQLServer: Buffer Manager\Buffer cache hit ratio&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;: Percentage of reads that come from memory (instead of having to go to disk)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;: This counter doesn’t take read-ahead reads into account. Read-ahead reads are an important type of physical read that use a special pre-fetching mechanism to pull data into memory. You could be doing &lt;em&gt;lots&lt;/em&gt; of reads from disk, and this counter won&amp;rsquo;t show them if they&amp;rsquo;re using read-ahead.&lt;/p&gt;
&lt;p&gt;This counter can give a false sense of security.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better solution&lt;/strong&gt;: Monitor LogicalDisk: Avg Disk Bytes/Read and Write, and Avg Disk sec/Read and Write. This gives you insight into latency when you&amp;rsquo;re accessing storage. The Avg Disk bytes counter can help you rule out blips or outliers from very small operations. You can also periodically sample the sys.dm_io_virtual_file_stats DMV in SQL Server for a database and file view of read and write MB and latency for the period between your samples (some code and math required).&lt;/p&gt;
&lt;h2 id="logicaldiskavg-disk-queue-length"&gt;LogicalDisk\Avg. Disk Queue Length&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;: Alert for slow storage&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;: Modern storage may have a queue, but very low latency&lt;/p&gt;
&lt;p&gt;This counter can cause false alarms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better solution&lt;/strong&gt;: Monitor LogicalDisk counters and/or sys.dm_io_virtual_file_stats as explained above.&lt;/p&gt;
&lt;h2 id="sql-server-access-methodspage-splitssec"&gt;SQL Server: Access Methods\Page Splits/sec&lt;/h2&gt;
&lt;p&gt;There are different types of page splits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An existing page in the middle of an index doesn’t have room for new data&lt;/li&gt;
&lt;li&gt;A new page needs to be added to the end of the index for new data&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;: count page split type #1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;: this counts &lt;em&gt;BOTH TYPES&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This counter can cause false alarms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better solution&lt;/strong&gt;: You can get fancy and track specific types of &lt;a href="https://www.sqlskills.com/blogs/jonathan/tracking-problematic-pages-splits-in-sql-server-2012-extended-events-no-really-this-time/"&gt;page splits with Extended Events&lt;/a&gt;. But honestly, I&amp;rsquo;m lazy, and I find it much easier to just regularly use an index maintenance solution that records which indexes are fragmented, and by how much. If an index is a &amp;ldquo;frequent flier&amp;rdquo; and gets highly fragmented very frequently, I&amp;rsquo;ll consider lowering the fillfactor for that index by 5%.&lt;/p&gt;
&lt;p&gt;Whichever method you&amp;rsquo;re using, look at what the index is based on and consider how it&amp;rsquo;s used before lowering fillfactor. There are some tables where the application using it is going to regularly do something to fragment the heck out of it periodically, and you may as well just leave the fillfactor as is.&lt;/p&gt;
&lt;h2 id="sql-server-access-methodsfull-scanssec"&gt;SQL Server: Access Methods\Full Scans/sec&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;: Alert if you have high table scans&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;: Not all scans are “full scans”! For example: TOP queries can have scan operators that feed into a TOP operator which controls the flow of the query, and stops the scan after its received all the rows it needs. The counter also gives no indication of size of tables scanned: one scan could be 15 rows, or 150GB, it will still count as one.&lt;/p&gt;
&lt;p&gt;This counter can cause false alarms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better solution&lt;/strong&gt;: If you&amp;rsquo;re concerned about physical reads, monitor the windows disk counters as described above. If you&amp;rsquo;re concerned about queries doing large amounts of logical reads, query those using the SQL Server DMVs with a query like this:&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/fb514b37878e04e5eb15faa434b29e65.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/fb514b37878e04e5eb15faa434b29e65"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;
&lt;h2 id="sqlserver-locks---average-wait-time-mslock-wait-time-ms-lock-waitssec"&gt;SQLServer: Locks - Average Wait Time (ms); Lock Wait Time (ms);  Lock Waits/sec&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The idea&lt;/strong&gt;: Alert if you have high lock waits&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;: These counters update when the lock wait &lt;em&gt;ends&lt;/em&gt;, not while it&amp;rsquo;s ongoing. Let&amp;rsquo;s say you have a query that&amp;rsquo;s blocked for five minutes. You&amp;rsquo;ll only see this in the perf monitor when it becomes un-blocked.&lt;/p&gt;
&lt;p&gt;These counters can cause confusion and make you look for blocking queries at the wrong times.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/lock-waits-perf-counters.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Better solution&lt;/strong&gt;:Monitor the SQL Server: General Statistics \ Processes Blocked counter instead. It gives you the number of sessions that are &lt;em&gt;currently&lt;/em&gt; blocked.&lt;/p&gt;
&lt;p&gt;If you want more information on troubleshooting and figuring out who is blocking who, check out my free course &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;Troubleshooting Blocking &amp;amp; Deadlocks for Beginners&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Register for Upcoming Free Webcasts on Indexes, Stats Maintenance, Query Tuning, and More</title><link>https://kendralittle.com/2017/06/02/register-for-upcoming-free-webcasts-on-indexes-stats-maintenance-query-tuning-and-more/</link><pubDate>Fri, 02 Jun 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/06/02/register-for-upcoming-free-webcasts-on-indexes-stats-maintenance-query-tuning-and-more/</guid><description>&lt;p&gt;I&amp;rsquo;ve got a whole bunch of free, live webcasts scheduled on SQL Server training! I&amp;rsquo;d love for you to join me for these sessions.&lt;/p&gt;
&lt;h2 id="schedule"&gt;Schedule&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/sqlworkbooks-calendar-e1496418023902.png" width="230"&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;Thu, June 8, 10AM Pacific - Should Developers Manage Index Maintenance?&lt;/li&gt;
&lt;li&gt;Thu, June 22, 10AM Pacific - Why an Index and Statistics Can Make a Query Slower&lt;/li&gt;
&lt;li&gt;Thu, June 29, 10AM Pacific - Statistics Maintenance Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;Thu, July 6, 10AM Pacific - SQL Server Management Studio Shortcuts &amp;amp; Secrets&lt;/li&gt;
&lt;li&gt;Thu, July 13, 10AM Pacific - The Weird, Wonderful World of Partitioned and Columnstore Indexes in Execution Plans&lt;/li&gt;
&lt;li&gt;Thu, July 20,10AM Pacific - How to Identify the Most Important Queries to Tune&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Registration for these events has now closed&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Database Mirroring Counters Missing from Perfmon?</title><link>https://kendralittle.com/2017/05/31/database-mirroring-counters-missing-from-perfmon/</link><pubDate>Wed, 31 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/31/database-mirroring-counters-missing-from-perfmon/</guid><description>&lt;p&gt;Collecting perfmon counters from SQL Server databases where you are using database mirroring is a little tricky&lt;/p&gt;
&lt;p&gt;The counters won&amp;rsquo;t behave &amp;ldquo;normally&amp;rdquo; until after you set up mirroring for a database.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/where-are-my-database-mirroring-perf-counters-e1495573843420.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="before-you-set-up-mirroring-the-counters-are-only-half-there"&gt;Before you set up mirroring, the counters are only half there&lt;/h2&gt;
&lt;p&gt;Before you set up mirroring, you can typically see the &amp;ldquo;Database Mirroring&amp;rdquo; object and individual counter names in Performance Monitor in Windows. But when you add the counters and click OK, they don&amp;rsquo;t show up in your graph!&lt;/p&gt;
&lt;p&gt;Also, when you run this query against your SQL Server instance, you get zero rows back:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_os_performance_counters&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%Database Mirroring%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="to-getthe-counters-to-work-you-need-to-set-up-mirroring-thenrestart-windows"&gt;To get the counters to work, you need to set up mirroring&amp;hellip; then restart Windows&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the bummer: after setting up database mirroring, I&amp;rsquo;ve never been able to query the counters or see the instances in perfmon without restarting Windows.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried &lt;em&gt;lots&lt;/em&gt; of things: restarting SQL Server? Tried that. Reloading the perf counters and restarting services (&lt;a href="https://blogs.technet.microsoft.com/pfelatam/2011/08/08/sql-performance-counters-are-missing/"&gt;as described in this SQL PFE post&lt;/a&gt;)? Tried that too!&lt;/p&gt;
&lt;p&gt;On multiple versions of SQL Server and Windows, I&amp;rsquo;ve had to restart the whole computer. (Most recently I&amp;rsquo;ve tested this with SQL Server 2008R2 on Windows Server 2008R2, and SQL Server 2016 on Windows Server 2012 R2.)&lt;/p&gt;
&lt;p&gt;There might well be a very specific dance you can do to get these counters to show without a full restart, but I haven&amp;rsquo;t found it! If you know the magic formula, please tell in the comments.&lt;/p&gt;
&lt;h2 id="the-good-news-availability-group-counters-are-built-differently"&gt;The good news: Availability Group counters are built differently&lt;/h2&gt;
&lt;p&gt;For availability groups, you can add or query the SQLServer: Availability Replica and SQLServer:Database Replica counters and collect &amp;ldquo;Total&amp;rdquo; before you ever set up an AG, or even enable AlwaysOn High Availability in the SQL Server configuration manager.&lt;/p&gt;</description></item><item><title>Why I am Inspired to Start Up Live Webcasts Again</title><link>https://kendralittle.com/2017/05/26/why-im-inspired-to-start-up-live-webcasts-again/</link><pubDate>Fri, 26 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/26/why-im-inspired-to-start-up-live-webcasts-again/</guid><description>&lt;p&gt;For a while now, I&amp;rsquo;ve been indulging in what feels like a huge guilty pleasure: an almost meeting-free existence. I&amp;rsquo;ve been living life scheduled on my own terms. I commit to appointments for workouts, volunteering, haircuts, and medical appointments, but not much else. I&amp;rsquo;ve been publishing pre-recorded videos and online courses which I can make whenever it feels right.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s been a couple of reasons for this. When it started, I wanted a major break from meetings. I wanted to see what it was like to have a more flexible schedule. It turns out I sometimes like working early, or late, and I like doing some writing on Sundays.&lt;/p&gt;
&lt;p&gt;For the last four months, there have been some practical reasons around this, too. There&amp;rsquo;s a house renovation and building boom going on in Portland, and three construction crews have been madly at work &lt;em&gt;directly outside my windows&lt;/em&gt; for months. Between the hours of 7 am and 5 pm, it&amp;rsquo;s been hard to predict when jackhammers, nail-guns, hollering, and other colorful noises might happen. (Bright sides to this: I&amp;rsquo;m getting a lot better at recording shorter segments. And I also took up meditation, which it turns out is great for me.)&lt;/p&gt;
&lt;p&gt;But as those construction projects are wrapping up (and thankfully, they&amp;rsquo;re close to done), I find that I&amp;rsquo;m inspired to schedule some&amp;hellip; &lt;em&gt;meetings&lt;/em&gt;. Specifically, I&amp;rsquo;m going to start scheduling live webcasts.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/microphone.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="i-attended-two-webcasts-in-the-last-two-weeks-and-they-were-awesome"&gt;I attended two webcasts in the last two weeks, and they were awesome&lt;/h2&gt;
&lt;p&gt;A while back, I found some really useful info on editing in Final Cut ProX on &lt;a href="https://larryjordan.com/"&gt;Larry Jordan&amp;rsquo;s website&lt;/a&gt;. I signed up for his newsletter, and I&amp;rsquo;ve attended some of his &lt;a href="https://larryjordan.com/weekly-webinar/"&gt;weekly webcasts&lt;/a&gt; recently, on the topics of using stills in FCPX, and multi-cam editing in FCPX.&lt;/p&gt;
&lt;p&gt;And I fell in love with webcasts all over again.&lt;/p&gt;
&lt;p&gt;There really is something about showing up for a live event and hearing a warm voice sometimes that&amp;rsquo;s pretty terrific. I haven&amp;rsquo;t lost my love of a-synchronicity, for sure, but Larry&amp;rsquo;s webcasts put me in the mood to change things up and get back to doing webcasts on my own.&lt;/p&gt;
&lt;p&gt;There may be some days when there&amp;rsquo;s a little unplanned background noise, but I&amp;rsquo;m sure we&amp;rsquo;ll make it through!&lt;/p&gt;
&lt;h2 id="im-going-to-do-a-mix-of-dear-sql-dba-questions-and-other-technical-topics"&gt;I&amp;rsquo;m going to do a mix of &amp;ldquo;Dear SQL DBA&amp;rdquo; questions and other technical topics&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/webcam-300x212.jpg" width="230"&gt;
&lt;/figure&gt;
My plan is to start scheduling a weekly webcast, all about SQL Server performance tuning and database administration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;Dear SQL DBA podcast and YouTube show&lt;/a&gt; will have a webcast every second week &amp;ndash; and it&amp;rsquo;ll still go out as a podcast and a YouTube video, too!&lt;/li&gt;
&lt;li&gt;On alternate weeks, I&amp;rsquo;ll do a webcast on SQL Server topics that I&amp;rsquo;m working on for video training, conference sessions, or things I&amp;rsquo;m blogging about.
&lt;ul&gt;
&lt;li&gt;Some of these will end up on YouTube afterward, some of them will be live only, it&amp;rsquo;ll depend on the topic&lt;/li&gt;
&lt;li&gt;Most of these will probably be demo-heavy and not very audio-only friendly, so they won&amp;rsquo;t be podcast episodes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&amp;rsquo;ll be able to sign up for each of the events in advance and set up calendar reminders, of course. I&amp;rsquo;m considering doing the webcast at two different times per day after a while, but I&amp;rsquo;m going to get started with just a single time slot before I get too crazy.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be working on all the plumbing of setting things up in the next few days, so expect to see more info about webcast sign-ups next week.&lt;/p&gt;
&lt;p&gt;Hooray!&lt;/p&gt;</description></item><item><title>Finding Queries that Cause Wait Stats in SQL Server</title><link>https://kendralittle.com/2017/05/25/finding-queries-that-cause-wait-stats-in-sql-server/</link><pubDate>Thu, 25 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/25/finding-queries-that-cause-wait-stats-in-sql-server/</guid><description>&lt;p&gt;You&amp;rsquo;ve got some troubling wait stats in SQL Server. How can you tell which queries are causing those waits?&lt;/p&gt;
&lt;p&gt;Learn the pros and cons of different techniques to track down the cause of both common and tricky waits in SQL Server, including CXPACKET, PAGEIOLATCH, LCK, RESOURCE_SEMAPHORE, and THREADPOOL waits.&lt;/p&gt;
&lt;p&gt;Get the scoop in this 35 minute video. Don&amp;rsquo;t have time to watch? Scroll down to read the article, or subscribe to the podcast to listen on the go (it&amp;rsquo;s on &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;iTunes&lt;/a&gt; or you can plug this URL into your favorite podcast app: &lt;a href="http://dear-sql-dba-podcast.libsyn.com/rss"&gt;http://dear-sql-dba-podcast.libsyn.com/rss&lt;/a&gt;)&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/DuPO1fL6PRw?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I recently got a great question from a reader:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are many articles and how-to&amp;rsquo;s about SQL Server waits. Plenty of scripts to check for biggest waits and types even all waits for chosen SPID which is executing.&lt;/p&gt;
&lt;p&gt;But how do I find the exact queries which are causing my waits?&lt;/p&gt;
&lt;p&gt;I’m using SQL Server 2008R2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="you-can-see-waits-for-all-executing-queries"&gt;You can see waits for all executing queries&lt;/h2&gt;
&lt;p&gt;As our questioner mentions&amp;ndash; you can see waits for a given SPID. With free tools like Adam Machanic&amp;rsquo;s &lt;a href="http://whoisactive.com/"&gt;sp_WhoIsActive procedure&lt;/a&gt;, you can see waits for &lt;em&gt;all&lt;/em&gt; currently executing queries&amp;ndash; not just one SPID, but everything that&amp;rsquo;s running.&lt;/p&gt;
&lt;p&gt;This can be useful for seeing, &amp;ldquo;Who is causing or having this wait right now,&amp;rdquo; and can sometimes be useful for home grown troubleshooting (I&amp;rsquo;ve got some examples below in the rare but dire waits section below).&lt;/p&gt;
&lt;h3 id="warning-there-are-some-interesting-gaps-in-looking-at-the-waits-for-currently-executing-queries"&gt;Warning: There are some interesting &amp;ldquo;gaps&amp;rdquo; in looking at the waits for currently executing queries&lt;/h3&gt;
&lt;p&gt;For example, you won&amp;rsquo;t see SOS_SCHEDULER_YIELD waits in sp_WhoIsActive. That&amp;rsquo;s because it doesn&amp;rsquo;t show up in the sys.dm_os_waiting_tasks DMV, which is the go-to DMV for current resource waits. SOS_SCHEDULER_YIELD is not technically a &amp;ldquo;resource&amp;rdquo; wait, it has to do with how queries periodically yield and are queued to get back on your CPUs: the cycle of cooperation that means everything isn&amp;rsquo;t just first-in, first out.&lt;/p&gt;
&lt;p&gt;There is a new twist to this. In SQL Server 2016, we have a new DMV called sys.dm_exec_session_wait_stats. It shows cumulative waits per session, and it does include SOS_SCHEDULER_YIELD. The information is cumulative for SPID and shows even when the SPID is sleeping, but goes away when it disconnects or is killed. This could be interesting in some systems or for some tests, but for systems where connections are used for lots of different queries, it may not be incredibly useful.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/tracing-waits.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="you-can-trace-query-waits-with-extended-events"&gt;You can trace query waits with Extended Events&lt;/h2&gt;
&lt;p&gt;I once had an extremely busy system where we had growing CMEMTHREAD waits. This is an unusual wait, and our question was: is this being caused by a single query, just a few queries, or all queries? We were able to answer this by setting up an extended events trace and looking at waits by query, but this had some downsides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extended Events has no GUI in 2008R2, and setting up and testing the scripts took a bit of time (more minor issue)&lt;/li&gt;
&lt;li&gt;Generating wait information by query on a very busy system generates a &lt;em&gt;lot&lt;/em&gt; of output, so we had to be careful to set up sampling and filtering so we didn&amp;rsquo;t impact performance (more major issue)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But we were able to use this to figure out that the wait was associated with &lt;em&gt;all&lt;/em&gt; queries, not a few queries, which helped us down our troubleshooting path.&lt;/p&gt;
&lt;p&gt;Because of the overhead of collecting all of this information with a trace, though, I have only used this for looking at a specific time frame and troubleshooting a specific wait, and often sampling the trace down is required. I wouldn&amp;rsquo;t set this up as part of regular full system monitoring of common waits due to concerns about impacting performance.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/current-waits.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="you-can-make-inferences-about-some-common-waits"&gt;You can make inferences about some common waits&lt;/h2&gt;
&lt;p&gt;For some common waits, it is easiest to make educated guesses. These methods aren&amp;rsquo;t perfect. Things like instance restarts/failovers, memory pressure and recompile hints remove information from the query cache. But they&amp;rsquo;re fast and easy, with low risk to performance. Examples:&lt;/p&gt;
&lt;h3 id="cxpacket-waits"&gt;CXPACKET waits&lt;/h3&gt;
&lt;p&gt;We know those are specific to parallel queries. Parallel queries typically have a higher average CPU time than an average duration. So you can query the SQL Server dynamic management views and look for your top CPU queries, and then look at those whose CPU time is higher than their duration. They are likely your top CXPACKET generators. Here&amp;rsquo;s &lt;a href="https://gist.github.com/LitKnd/a351c705958d71d6fa856cba136cd3f3"&gt;a sample query to find top CPU queries&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="pageiolatch_xx-waits"&gt;PAGEIOLATCH_XX waits&lt;/h3&gt;
&lt;p&gt;These are waits for pulling pages from storage into memory. Typically queries that do large amounts of physical reads are your big suspects for this. You can query the DMVs and look for your queries that do the highest average physical reads or writes, and start evaluating them. Here &lt;a href="https://gist.github.com/LitKnd/2f1dc3229604e7319fc2fa86f38745f6"&gt;are some sample queries to find top queries for physical reads and writes&lt;/a&gt;.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: there's a more detailed option for finding the cause of &lt;a href="#pageiolatch_2"&gt;PAGEIOLATCH waits below&lt;/a&gt;.
&lt;/div&gt;
&lt;h3 id="lck_m_xx-waits"&gt;LCK_M_XX waits&lt;/h3&gt;
&lt;p&gt;These are lock waits associated with being blocked. For these waits, I would use something like the blocked process report if I was troubleshooting blocking and wanted a simple way to capture who is blocking who.&lt;/p&gt;
&lt;p&gt;Right now you can &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;enroll for free in the Troubleshooting Blocking &amp;amp; Deadlocks in SQL Server course&lt;/a&gt; to learn how to fight blocking.&lt;/p&gt;
&lt;h2 id="you-can-get-crafty-with-some-fairly-rare-but-dire-waits"&gt;You can get crafty with some (fairly) rare but dire waits&lt;/h2&gt;
&lt;h3 id="resource_semaphore-waits"&gt;RESOURCE_SEMAPHORE waits&lt;/h3&gt;
&lt;p&gt;This is a wait associated with low &amp;ldquo;query workspace memory&amp;rdquo; and it causes the SQL Server to feel like it&amp;rsquo;s not working. You can still use the dedicated admin connection, but &amp;ldquo;normal&amp;rdquo; monitoring queries stop working when it gets very bad.&lt;/p&gt;
&lt;p&gt;For this one, there&amp;rsquo;s a performance counter called Memory Manager\Memory Grants Pending. In one case where we had these waits and no full fledged monitoring system, I set up a SQL Server Agent Performance Alert based on this counter. Whenever it rose above 0, the alert triggered a job that recorded a few samples of sp_WhoIsActive and a few other queries to tables. This helped us see what queries had the wait, and what queries were running that had large memory grants&amp;ndash; because the alert triggered the job before the waits got too bad and we could see the start of the problem. We then could troubleshoot ways to reduce the memory grants for the executing queries.&lt;/p&gt;
&lt;h3 id="threadpool-waits"&gt;THREADPOOL waits&lt;/h3&gt;
&lt;p&gt;This is a wait associated with not having enough threads - it means there&amp;rsquo;s a lot of active processes, so many that the SQL Server can&amp;rsquo;t make more threads without risking stability of the OS. This can be associated with problems in connection pooling, or sometimes it happens with some applications if you get a lot of blocking &amp;ndash; when those queries can&amp;rsquo;t complete, some applications just start taking out a lot of other connections.&lt;/p&gt;
&lt;p&gt;Similarly to RESOURCE_SEMAPHORE, you can still use the dedicated admin connection, but normal queries &amp;ldquo;stop&amp;rdquo; working when this gets really bad.&lt;/p&gt;
&lt;p&gt;In one case with this one, the connection pooling setup looked normal, and I highly suspected blocking was involved. So I set up a SQL Server Agent Performance Alert based on the General Statistics\Processes Blocked counter, and when that rose above 1 we captured output from sp_WhoIsActive to a table, along with capturing a few other diagnostic queries. This allowed us to confirm that blocking was the root cause of the issue and see what the blocker was doing, because again it captured activity as the waits were building up.&lt;/p&gt;
&lt;h2 id="knowing-who-is-waiting-is-often-not-enough"&gt;Knowing who is waiting is often not enough!&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s revisit the question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How do I find the exact queries which are causing my waits?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One interesting point about this is that the query waiting is not always the query &lt;em&gt;causing&lt;/em&gt; the wait.&lt;/p&gt;
&lt;h3 id="the-query-waiting-for-a-lock-has-the-lck_m_-wait"&gt;The query waiting for a lock has the LCK_M_?? wait&lt;/h3&gt;
&lt;p&gt;But it&amp;rsquo;s just the victim! The query &lt;em&gt;holding&lt;/em&gt; the lock who is blocking does not have the wait. (Or if the blocker does have a lock wait, we want to know who is at the root of the whole blocking chain and holding the locks that are causing it all: they aren&amp;rsquo;t waiting.)&lt;/p&gt;
&lt;h3 id="the-query-waiting-for-query-workspace-memory-has-the-resource_semaphore-wait"&gt;The query waiting for query workspace memory has the RESOURCE_SEMAPHORE wait&lt;/h3&gt;
&lt;p&gt;This is another bystander/victim. What we want to know is what queries have memory grants, how many of the queries are their, how big are their memory grants, and should they be that big? They may not have any waits at all!&lt;/p&gt;
&lt;h3 id="even-for-pageiolatch_-waits-a-query-having-this-wait-might-well-be-an-innocent-bystander"&gt;Even for PAGEIOLATCH_?? waits, a query having this wait might well be an innocent bystander&lt;/h3&gt;
&lt;p&gt;Perhaps the instance has recently started up, and the query wants pages that are frequently accessed, but it happens to be the first that reads them into memory, and it&amp;rsquo;s slow. Or perhaps a whole bunch of other queries took over the buffer pool for a while, and now this &amp;ldquo;normal&amp;rdquo; query needs to read frequently read pages back into memory. What we really want to know is what queries were running when our buffer pool memory started &amp;ldquo;churning&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;An easier way to find the cause of this wait might be to track the &amp;ldquo;Buffer Manager: Page Life Expectancy&amp;rdquo; performance counter, and look for times when it starts to take a sharp nose-dive. Then look at what queries were running at that point in time - particularly those that did a lot of reads. (If you aren&amp;rsquo;t tracking this counter, you can make a more general guess by looking at DMVs for your top queries doing the highest physical reads after the system has been up for a while, as mentioned above.)&lt;/p&gt;
&lt;h3 id="these-are-just-a-fewexamples"&gt;These are just a few examples&lt;/h3&gt;
&lt;p&gt;For many waits, we need to know about what&amp;rsquo;s executing or has an open transaction, their session status, what resources they are using, if they have any (different) waits, and sometimes information about their execution plans. We need a &lt;em&gt;lot&lt;/em&gt; more info than just query + wait.&lt;/p&gt;
&lt;h2 id="extra-investmentmakes-this-easier-in-older-versions-of-sql-server"&gt;Extra investment makes this easier in older versions of SQL Server&lt;/h2&gt;
&lt;p&gt;Professional monitoring tools that capture overall waits, as well as executing queries at different times and information about blocking make it easier to solve these. You still need to make some educated guesses, but you don&amp;rsquo;t have to &amp;ldquo;rig up&amp;rdquo; things to capture the information as often, because it&amp;rsquo;s regularly collected.&lt;/p&gt;
&lt;h2 id="looks-like-query-store-is-going-to-make-this-much-easier-in-future-versions"&gt;Looks like Query Store is going to make this much easier in future versions!&lt;/h2&gt;
&lt;p&gt;In SQL Server 2017, we have wait stats information coming into Query Store. I haven&amp;rsquo;t kicked the tires on that yet, but it looks like that is going to make answering your question much easier in future versions of SQL Server.&lt;/p&gt;</description></item><item><title>When a Nonclustered Index and Statistics Make a Query Slower</title><link>https://kendralittle.com/2017/05/24/when-a-nonclustered-index-and-statistics-make-a-query-slower/</link><pubDate>Wed, 24 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/24/when-a-nonclustered-index-and-statistics-make-a-query-slower/</guid><description>&lt;p&gt;Nonclustered indexes are awesome in SQL Server: they can get you huge performance gains.&lt;/p&gt;
&lt;p&gt;But we can&amp;rsquo;t always create the perfect index for every query. And sometimes when SQL Server finds an index that isn&amp;rsquo;t quite perfect and decides to use it, it might make your query slower instead of faster.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/dinosaur-create-index.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s an example of why that can happen, and some reasons why if you hit something like this, the FORCESCAN table hint may help (and also why you should be careful with that).&lt;/p&gt;
&lt;h2 id="the-setup"&gt;The setup&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve restored the &lt;a href="https://github.com/LitKnd/BabbyNames/releases"&gt;large BabbyNames sample database&lt;/a&gt; and created a couple of indexes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_ref_FirstName_INCLUDES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_dbo_FirstNameByBirthDate_1966_2015_FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="meetmy-slow-query"&gt;Meet my slow query&lt;/h2&gt;
&lt;p&gt;My query has a simple join, and a GROUP BY clause. We&amp;rsquo;re looking for the count of all the babies born named &amp;ldquo;Matthew&amp;rdquo;, grouped by Gender:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Matthew&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="sql-server-thinks-this-query-is-going-to-be-cheap"&gt;SQL Server thinks this query is going to be cheap&lt;/h2&gt;
&lt;p&gt;The query has cost of 19.75. SQL Server estimates that it&amp;rsquo;s going to get 6,016 rows back from dbo.FirstNameByBirthDate_1966_2015 for all those Matthews.&lt;/p&gt;
&lt;p&gt;Since that&amp;rsquo;s not a lot of rows, it decides to use the narrow nonclustered index on FirstNameId to find the Matthews, and then go do a key lookup to pick up the Gender column in the clustered index of the table. Here is what the estimated execution plan looks like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query1-estimated-plan.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="but-sql-server-is-underestimating-the-number-of-matthews-by-a-lot"&gt;But SQL Server is underestimating the number of Matthews by a lot&lt;/h2&gt;
&lt;p&gt;This table has a row for every baby named Matthew in the United States between 1966 and 2015. There are a &lt;em&gt;lot&lt;/em&gt; more Matthews than 6K. Our estimate is off by around 1.4 million.&lt;/p&gt;
&lt;p&gt;When SQL Server chooses this plan, the query takes around &lt;em&gt;&lt;strong&gt;13 seconds&lt;/strong&gt;&lt;/em&gt; to execute. Running all those nested loops with a single thread isn&amp;rsquo;t quick!&lt;/p&gt;
&lt;p&gt;Spoiler: if this nonclustered index didn&amp;rsquo;t exist (or wasn&amp;rsquo;t selected), the query would execute in &lt;strong&gt;&lt;em&gt;around 5 seconds (instead of 13 seconds)&lt;/em&gt;&lt;/strong&gt;, just scanning the clustered table_._&lt;/p&gt;
&lt;h2 id="why-is-the-estimate-so-low"&gt;Why is the estimate so low?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using the new cardinality estimator in SQL Server, so I used a few trace flags (&lt;a href="http://sqlblog.com/blogs/paul_white/archive/2011/09/21/how-to-find-the-statistics-used-to-compile-an-execution-plan.aspx"&gt;more on those from Paul White here&lt;/a&gt;) to get SQL Server to write out some information about which statistics it used to my &amp;lsquo;Messages&amp;rsquo; tab when I compiled the query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Matthew&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2363&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Among lots of other details, it told me &amp;ldquo;Loaded histogram for column QCOL: [fnbd].FirstNameId from stats with id 4&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I used dynamic management views to confirm that my statistic with id 4 on FirstNameByBirthDate_1966_2015 is the stat for the index ix_dbo_FirstNameByBirthDate_1966_2015_FirstNameId.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s look at that stat!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SHOW_STATISTICS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_dbo_FirstNameByBirthDate_1966_2015_FirstNameId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the statistic, with a few minor embellishments&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistics-on-the-table-1024x490.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Things to notice, by number:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;Rows Sampled&amp;rdquo; in the header is equal to all the rows in the table. This statistic was created when the index was created, and so it automatically got &amp;ldquo;fullscan&amp;rdquo;. SQL Server sampled &lt;em&gt;all&lt;/em&gt; of the rows when it created this stat.&lt;/li&gt;
&lt;li&gt;The blue highlighted row is in the section called the Histogram of the statistic. The FirstNameId for &amp;lsquo;Matthew&amp;rsquo; is 28,073. This value happened to get its own row in the histogram, and SQL Server knows that there are approximately 1,451,969 rows in this table of Matthews. That&amp;rsquo;s way more than the estimate of  6,016! &lt;em&gt;The histogram didn&amp;rsquo;t get used&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The &amp;ldquo;All density&amp;rdquo; number for just the FirstNameID column is 3.774155E-05 &amp;ndash; aka 0.00003774155. This number is in what&amp;rsquo;s called the &amp;ldquo;density vector&amp;rdquo; for the index, and it&amp;rsquo;s used for when SQL Server is going to guess how many rows come back for an &amp;ldquo;average&amp;rdquo; FirstNameId (not a specific FirstNameId). And looking at our query, &lt;em&gt;we didn&amp;rsquo;t give it a specific FirstNameId&lt;/em&gt;. We put the predicate over on ref.FirstName, using the FirstName column.&lt;/li&gt;
&lt;li&gt;Rows = 159,405,121. This is the other ingredient to our formula to &amp;ldquo;guess how many rows exist for an average FirstNameId.&amp;rdquo;
&lt;ul&gt;
&lt;li&gt;All density * rows =  0.00003774155 * 159,405,121 = &lt;em&gt;&lt;strong&gt;6,016.19634447755&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To be clear, the problem here is &lt;em&gt;not&lt;/em&gt; the new cardinality estimator. The legacy cardinality estimator also chooses a nested loop plan and is just as slow for this query.&lt;/p&gt;
&lt;h2 id="the-slow-performance-is-because-of-the-way-we-wrote-our-query"&gt;The slow performance is because of the way we wrote our query&lt;/h2&gt;
&lt;p&gt;We wrote our query putting a predicate on FirstName on the dimension table, ref.FirstName, then joined over to dbo.FirstNameByBirthDate_1966_2015. SQL Server has to generate the execution plan for the query before it runs. It can&amp;rsquo;t query ref.FirstName and find out what the FirstNameId is for Matthew, then use that to figure out what kind of join to use.&lt;/p&gt;
&lt;p&gt;(At least not yet. Plans like this can potentially be fixed by the Adaptive Join feature in future releases, but it doesn&amp;rsquo;t cover this in the initial SQL Server 2017 release. They can&amp;rsquo;t tackle everything at once.)&lt;/p&gt;
&lt;p&gt;Instead, SQL Server has to say, &amp;ldquo;Well, for any given name that I join on, what looks like the best bet?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s why it uses the density vector on the statistic multiplied by the rowcount. There&amp;rsquo;s nothing wrong with the statistic.&lt;/p&gt;
&lt;p&gt;What if we wrote our query differently and specified the FirstNameId for Matthew?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28073&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, SQL Server looks at the histogram for the FirstNameId and gives us a very different estimated plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/plan-when-specifying-firstnameid.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;But it can only do this because we gave it the FirstNameId.&lt;/p&gt;
&lt;p&gt;Knowing about all those Matthews at the time of compilation, SQL Server decides it may as well just go ahead and scan the clustered index using parallelism. It also asks for a nonclustered index on Key (FirstNameId) INCLUDE (Gender).&lt;/p&gt;
&lt;p&gt;This query takes &lt;strong&gt;&lt;em&gt;around &lt;strong&gt;5&lt;/strong&gt; seconds (instead of 13 seconds)&lt;/em&gt;&lt;/strong&gt;. Scanning that clustered index isn&amp;rsquo;t awesome, but it&amp;rsquo;s more than twice as fast as using the imperfect nonclustered index on FirstNameId and then going back to look up Gender.&lt;/p&gt;
&lt;h2 id="is-there-another-way-to-fix-this"&gt;Is there another way to fix this?&lt;/h2&gt;
&lt;p&gt;This is a pretty simple example. You can&amp;rsquo;t always just change the query to specify just the right predicate like FirstNameId = 28073.&lt;/p&gt;
&lt;p&gt;Sometimes, the FORCESCAN table hint can help. Here&amp;rsquo;s what &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table"&gt;the documentation explains (in brief, click to read more detail including limitations)&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Introduced in SQL Server 2008 R2 SP1, this hint specifies that the query optimizer use only an index scan operation as the access path to the referenced table or view. The FORCESCAN hint can be useful for queries in which the optimizer underestimates the number of affected rows and chooses a seek operation rather than a scan operation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we know that every time we want this query to run, we do &lt;em&gt;not&lt;/em&gt; want it to do a seek on an index, we could add this hint. We don&amp;rsquo;t even have to specify an index with it, we can do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FORCESCAN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fnbd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Matthew&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get a slightly different estimated plan&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/forcescan-plan-1024x177.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;But again the query completes in around &lt;strong&gt;&lt;em&gt;5 seconds instead of 13&lt;/em&gt;&lt;/strong&gt;.  And again it registers a request for an index on Key (FirstNameId) INCLUDE (Gender).&lt;/p&gt;
&lt;h2 id="what-if-we-use-forcescan-and-then-someone-adds-the-perfect-index"&gt;What if we use FORCESCAN and then someone adds the perfect index?&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say that we found this slow query, and for whatever reason it didn&amp;rsquo;t make sense to give it the &amp;ldquo;perfect&amp;rdquo; index. So we added a FORCESCAN hint to make it faster.&lt;/p&gt;
&lt;p&gt;But later on, we found other queries who would use the same index that this query wanted. And eventually we ditched the index on just FirstNameId and replaced it with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_dbo_FirstNameByBirthDate_1966_2015_FirstNameId_Includes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This index is great for this query! It makes our original query (with no hints) complete in less than half a second, using a simple index seek!&lt;/p&gt;
&lt;p&gt;But if we have that FORCESCAN hint in place, SQL Server can use the new, perfect index but&amp;hellip;. yeah, it&amp;rsquo;s forced to scan it. The hint name isn&amp;rsquo;t kidding.&lt;/p&gt;
&lt;p&gt;Forcing the scan of the perfect index takes around &lt;strong&gt;&lt;em&gt;six seconds&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;When you add a non-clustered index, it&amp;rsquo;s possible for this to cause performance regressions in some of your queries.&lt;/p&gt;
&lt;p&gt;When you see a low estimate in a query in SQL Server, the problem isn&amp;rsquo;t always that the statistics are &amp;ldquo;bad&amp;rdquo;. SQL Server may have very accurate data in the statistics, but may not be able to use it perfectly because of the way the query is written.&lt;/p&gt;
&lt;p&gt;The FORCESCAN table hint can be used to change the behavior of a query without specifying an index  by name &amp;ndash; but if you use this hint, you need to periodically check and make sure that the hint is still making the query faster, not slower.&lt;/p&gt;
&lt;h2 id="want-to-learn-about-more-query-hints"&gt;Want to learn about more query hints?&lt;/h2&gt;
&lt;p&gt;Check out my free course, &lt;a href="https://kendralittle.com/course/query-tuning-with-hints-optimizer-hotfixes/"&gt;Query Tuning with Hints &amp;amp; Optimizer Hotfixes&lt;/a&gt;!&lt;/p&gt;</description></item><item><title>Removing Query Hints with Plan Guides (Dear SQL DBA Episode 43)</title><link>https://kendralittle.com/2017/05/18/removing-query-hints-with-plan-guides-dear-sql-dba-episode-43/</link><pubDate>Thu, 18 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/18/removing-query-hints-with-plan-guides-dear-sql-dba-episode-43/</guid><description>&lt;p&gt;If you need to add, remove, or replace hints from ad-hoc queries where you can&amp;rsquo;t change the code, plan guides can help. See a demo of removing a query hint from parameterized TSQL run from an application, and get tips on how to make your plan guides work in SQL Server.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://gist.github.com/LitKnd/157177799d4fe4e5ad7ad78d53afbfc5"&gt;code from the demo is here&lt;/a&gt;. Links for more info are below the video. Have fun!&lt;/p&gt;
&lt;h2 id="option-1-listen-to-the-30-minute-audio-podcast-episode-or-download-it"&gt;Option 1: Listen to the 30 minute audio podcast episode (or download it!)&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: You can listen on the run by subscribing to the podcast &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;h2 id="option-2-watch-the-youtube-video"&gt;Option 2: Watch the YouTube video&lt;/h2&gt;
&lt;p&gt;This is the exact same content as in the audio podcast, but with visuals of the slides and demos.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/7yKOIoTu1-M?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="further-reading"&gt;Further reading&lt;/h2&gt;
&lt;p&gt;The video shows creating a plan guide with sp_create_plan_guide to remove a query hint, but you can use plan guides to do much more!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can add or remove table hints (such as an index hint or a FORCESCAN hint), using slightly different syntax with sp_create_plan_guide. See &lt;a href="https://technet.microsoft.com/en-us/library/bb677261"&gt;examples in Books Online here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can force parameterization of specific queries using sp_create_plan_guide to create a &amp;lsquo;TEMPLATE&amp;rsquo; type plan guide. See &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/create-a-plan-guide-for-parameterized-queries"&gt;example syntax on this type of plan guide here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can &amp;ldquo;freeze&amp;rdquo; an execution plan so that it is always used for the query. For this one, you use the procedure sp_create_plan_guide_from_handle. See code on &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-create-plan-guide-from-handle-transact-sql"&gt;how to do this here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Perfmon: Batch Requests/sec counts whole batches, not statements</title><link>https://kendralittle.com/2017/05/16/perfmon-batch-requestssec-counts-whole-batches-not-statements/</link><pubDate>Tue, 16 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/16/perfmon-batch-requestssec-counts-whole-batches-not-statements/</guid><description>&lt;p&gt;The name of the &amp;ldquo;SQL Statistics \ Batch Requests/sec&amp;rdquo; counter is confusing: exactly what is a request? The request is the WHOLE batch. See a demo of this counter in this quick 5 minute video.&lt;/p&gt;
&lt;h2 id="video-demo"&gt;Video Demo&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/yp0ZscY3dqM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Batch Mode Hacks for Rowstore Queries in SQL Server</title><link>https://kendralittle.com/2017/05/11/batch-mode-hacks-for-rowstore-queries-in-sql-server/</link><pubDate>Thu, 11 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/11/batch-mode-hacks-for-rowstore-queries-in-sql-server/</guid><description>&lt;h2 id="whats-batch-mode"&gt;What&amp;rsquo;s batch mode?&lt;/h2&gt;
&lt;p&gt;Batch mode was introduced as a way to help SQL Server process data from columnstore indexes faster. The whole idea with columnstore is that you pull big compressed sets of rows out for aggregation or other operations in big chunks.&lt;/p&gt;
&lt;p&gt;Batch mode is a way that operators can work on a &amp;ldquo;batch&amp;rdquo; of up to 900 values at a time, instead of working on individual rows. Batch mode can reduce the overhead of metadata and make more efficient use of your CPUs.&lt;/p&gt;
&lt;h2 id="batch-mode-requires-a-columnstore-index-be-present-on-a-table-in-the-query-but-it-doesnt-require-it-to-be-used-in-the-plan"&gt;Batch mode requires a columnstore index be present on a table in the query (but it doesn&amp;rsquo;t require it to be used in the plan)&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re in a weird situation in SQL Server with batch mode at this point.  (As of this writing, &amp;ldquo;current&amp;rdquo; released version is SQL Server 2016 SP1). Batch mode operators will only show up in your query plan if you&amp;rsquo;re referencing a table with some kind of columnstore index.&lt;/p&gt;
&lt;p&gt;However, your query plan doesn&amp;rsquo;t have to &lt;em&gt;use&lt;/em&gt; the columnstore index.&lt;/p&gt;
&lt;p&gt;This means there&amp;rsquo;s a few ways to trick SQL Server into using batch mode without really using columnstore.&lt;/p&gt;
&lt;h2 id="hack-1-theimpossible-filtered-nonclustered-columnstore-index"&gt;Hack #1: the impossible filtered nonclustered columnstore index&lt;/h2&gt;
&lt;p&gt;Itzik Ben-Gan wrote about this hack in his article on the &lt;a href="http://sqlmag.com/sql-server/what-you-need-know-about-batch-mode-window-aggregate-operator-sql-server-2016-part-1"&gt;Batch Mode Window Aggregate operator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Basically, the hack is to create a filtered nonclustered columnstore index that can&amp;rsquo;t have any rows in it, like this:&lt;/p&gt;
&lt;p&gt;CREATE NONCLUSTERED COLUMNSTORE INDEX nccx_agg_FirstNameByYearState
ON agg.FirstNameByYearState
(FirstNameId)
WHERE FirstNameId = -1 and FirstNameId = -2;
GO&lt;/p&gt;
&lt;p&gt;See that filter? Ain&amp;rsquo;t no rows getting past that!&lt;/p&gt;
&lt;p&gt;This hack only works on SQL Server 2016+, because that&amp;rsquo;s when we got &lt;a href="https://kendralittle.com/2016/11/10/filtered-indexes-rowstore-vs-nonclustered-columnstore/"&gt;filtered nonclustered columnstore indexes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While that nonclustered columnstore index is going to have very minimal overhead, you do open yourself up to the potential of hitting weird execution plans &amp;ndash; although in my test case, SQL Server wisely chose to ignore the index.&lt;/p&gt;
&lt;h2 id="hack-2-thebogus-left-join-to-an-empty-columnstore-table"&gt;Hack #2: the bogus left join to an empty columnstore table&lt;/h2&gt;
&lt;p&gt;To get batch mode to show up, you need to reference a table with columnstore somewhere in the query. But that&amp;rsquo;s a pretty lenient rule, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The table doesn&amp;rsquo;t need to be used in the execution plan at all, it can be ruled out&lt;/li&gt;
&lt;li&gt;You can get batch mode operators for OTHER tables just by referencing that columnstore table in your TSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This hack basically looks like this:&lt;/p&gt;
&lt;p&gt;CREATE TABLE dbo.hack (i int identity);
GO
CREATE NONCLUSTERED COLUMNSTORE INDEX nccx_hack on dbo.hack(i);
GO
/* and then in the query you&amp;rsquo;re hacking&amp;hellip; */&lt;/p&gt;
&lt;p&gt;LEFT JOIN dbo.hack on 1=0&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure if Niko Neugebauer, Paul White, or some other scoundrel came up with this brilliant mess, but that bogus outer join to dbo.Hack won&amp;rsquo;t show up in an execution plan. It&amp;rsquo;s valid TSQL but the optimizer sees it for the garbage it is and just optimizes it out.&lt;/p&gt;
&lt;p&gt;You can even do this trick with a temp table #Hack.&lt;/p&gt;
&lt;p&gt;This hack requires changing your code, but &lt;em&gt;doesn&amp;rsquo;t&lt;/em&gt; require SQL Server 2016+.&lt;/p&gt;
&lt;h2 id="hack-3-not-recommended-database-compatibility-level-change-to-get-batch-mode"&gt;Hack #3 (not recommended): database compatibility level change to get batch mode&lt;/h2&gt;
&lt;p&gt;First up: just changing your compat level doesn&amp;rsquo;t get you batch mode. You&amp;rsquo;ve got to have a legit columnstore index on a table reference in your query, or be hacking one in somehow.&lt;/p&gt;
&lt;p&gt;But sometimes that&amp;rsquo;s not enough. Niko has written about some cases where batch mode is available (due to columnstore existence), but &lt;a href="http://www.nikoport.com/2016/06/21/columnstore-indexes-part-85-important-batch-mode-changes-in-sql-server-2016/"&gt;isn&amp;rsquo;t being used in SQL Server 2016 compat level 130 due to hints in the query&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In some cases lowering the database compat level to 120 might help that query use batch mode, but DANGER! If you do that, you&amp;rsquo;ll lose significant improvements made for batch mode that you get at compat level 130.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re facing that problem, you probably want to find a different way to work it out.&lt;/p&gt;
&lt;h2 id="not-a-hack-you-could-just-use-columnstore"&gt;Not a hack: you could just use columnstore&lt;/h2&gt;
&lt;p&gt;This is hopefully obvious, but potentially you could use batch mode in a query with a real, populated columnstore index. These hacks are just for times where columnstore isn&amp;rsquo;t a fit for your workload.&lt;/p&gt;
&lt;h2 id="want-more-batch-mode-vote-up-this-suggestion-in-microsoft-connect"&gt;Want more batch mode? Vote up this suggestion in Microsoft Connect&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/938021/implement-batch-mode-support-for-row-store"&gt;Suggestion: implement batch mode for rowstore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It sounds like this is going to get implemented, but developer time is precious and &lt;em&gt;your vote would help&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="demo-video"&gt;Demo video&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Demo code from the video is at the bottom of the page&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/C8yQh25r8vM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="related-reading"&gt;Related reading&lt;/h2&gt;
&lt;p&gt;Columnstore Indexes – Query Performance: &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-query-performance"&gt;https://&lt;/a&gt;&lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-query-performance"&gt;docs.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-query-performance&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Important Batch Mode Changes in SQL Server 2016 by Niko Neugebauer: &lt;a href="http://www.nikoport.com/2016/06/21/columnstore-indexes-part-85-important-batch-mode-changes-in-sql-server-2016/"&gt;http://www.nikoport.com/2016/06/21/columnstore-indexes-part-85-important-batch-mode-changes-in-sql-server-2016&lt;/a&gt;&lt;a href="http://www.nikoport.com/2016/06/21/columnstore-indexes-part-85-important-batch-mode-changes-in-sql-server-2016/"&gt;/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What You Need to Know about the Batch Mode Window Aggregate Operator in SQL Server 2016: Part 1 by Itzik Ben-Gan: &lt;a href="http://sqlmag.com/sql-server/what-you-need-know-about-batch-mode-window-aggregate-operator-sql-server-2016-part-1"&gt;http://&lt;/a&gt;&lt;a href="http://sqlmag.com/sql-server/what-you-need-know-about-batch-mode-window-aggregate-operator-sql-server-2016-part-1"&gt;sqlmag.com/sql-server/what-you-need-know-about-batch-mode-window-aggregate-operator-sql-server-2016-part-1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What exactly can SQL Server 2014 execute in batch mode? Answer by Paul White: &lt;a href="https://dba.stackexchange.com/questions/97650/what-exactly-can-sql-server-2014-execute-in-batch-mode"&gt;https://&lt;/a&gt;&lt;a href="https://dba.stackexchange.com/questions/97650/what-exactly-can-sql-server-2014-execute-in-batch-mode"&gt;dba.stackexchange.com/questions/97650/what-exactly-can-sql-server-2014-execute-in-batch-mode&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="demo-code"&gt;Demo code&lt;/h2&gt;
&lt;script src="https://gist.github.com/LitKnd/157177799d4fe4e5ad7ad78d53afbfc5.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/157177799d4fe4e5ad7ad78d53afbfc5"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>New Course! Query Tuning with Hints &amp; Optimizer Hotfixes</title><link>https://kendralittle.com/2017/05/10/new-course-query-tuning-with-hints-optimizer-hotfixes/</link><pubDate>Wed, 10 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/10/new-course-query-tuning-with-hints-optimizer-hotfixes/</guid><description>&lt;p&gt;Want to up your query tuning game? For a limited time, you can snag a free enrollment to the new course, &lt;a href="https://kendralittle.com/course/query-tuning-with-hints-optimizer-hotfixes/"&gt;Query Tuning with Hints &amp;amp; Optimizer Hotfixes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="about-the-course"&gt;About the Course&lt;/h2&gt;
&lt;p&gt;Learn the pros and cons of using hints and optimizer hotfixes in SQL Server, and see how hints can give you insight into the optimization process. Sorry, this free giveaway has ended.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/jKV14MYCCcw?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>SQLServer:Databases(_Total)\Transactions/sec vs SQL Statistics\Batch Requests/sec (video)</title><link>https://kendralittle.com/2017/05/08/sqlserverdatabases_totaltransactionssec-vs-sql-statisticsbatch-requestssec-video/</link><pubDate>Mon, 08 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/08/sqlserverdatabases_totaltransactionssec-vs-sql-statisticsbatch-requestssec-video/</guid><description>&lt;p&gt;Perfmon counters are great for measuring workload, but choosing which counter to baseline can be confusing.&lt;/p&gt;
&lt;h2 id="the-transactionssec-counter-has-big-blind-spots"&gt;The Transactions/sec counter has big blind spots&lt;/h2&gt;
&lt;p&gt;Watch a quick 5 minute demo showing that the SQL Statistics\Batch Requests/sec counter sees more of your workload than the Databases(_Total)\Transactions/sec counter does.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/aIK6XPSkLQc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="want-more-perfmon-tips-for-sql-server"&gt;Want more perfmon tips for SQL Server?&lt;/h2&gt;
&lt;p&gt;Check out my &lt;a href="https://www.youtube.com/playlist?list=PLoM-GGCV9ZrKB7crLNFLiT3BbGZkqkPuI"&gt;YouTube playlist of perfmon tips here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Should I Get Certified as a DBA? (Dear SQL DBA Episode 41)</title><link>https://kendralittle.com/2017/05/04/should-i-get-certified-as-a-dba-dear-sql-dba-episode-41/</link><pubDate>Thu, 04 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/04/should-i-get-certified-as-a-dba-dear-sql-dba-episode-41/</guid><description>&lt;p&gt;Find out if getting certified will help you land an entry level DBA job. If you do want to get certified, get Kendra&amp;rsquo;s tips on preparing for the exam in this 17 minute episode.&lt;/p&gt;
&lt;h2 id="option-1-listen-to-or-download-the-audio-podcast-episode"&gt;Option 1: Listen to or download the audio podcast episode&lt;/h2&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;LISTEN&lt;/strong&gt;: You can listen on the run by subscribing to the podcast &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;on iTunes&lt;/a&gt;, &lt;a href="https://goo.gl/app/playmusic?ibi=com.google.PlayMusic&amp;isi=691797987&amp;ius=googleplaymusic&amp;link=https://play.google.com/music/m/Ivy7ctr66hgx4jfwi7tsasixheu?t%3DDear_SQL_DBA"&gt;on Google Play&lt;/a&gt;, or plug &lt;a href="http://dearsqldba.libsyn.com/rss"&gt;this RSS feed&lt;/a&gt; into your favorite podcast app.
&lt;/div&gt;
&lt;h2 id="option-2-watch-the-youtube-video"&gt;Option 2: Watch the YouTube video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/6oOGXoeQk2s?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="links-from-this-episode"&gt;Links from this episode&lt;/h2&gt;
&lt;p&gt;SQL Server User Groups: &lt;a href="http://www.pass.org/Community/Groups/LocalGroups.aspx"&gt;http://www.pass.org/Community/Groups/LocalGroups.aspx&lt;/a&gt; SQL Saturdays: &lt;a href="http://sqlsaturday.com/"&gt;http://sqlsaturday.com/&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Checking for the Existence of Global Temp Table in TSQL</title><link>https://kendralittle.com/2017/05/03/checking-for-the-existence-of-global-temp-table-in-tsql/</link><pubDate>Wed, 03 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/03/checking-for-the-existence-of-global-temp-table-in-tsql/</guid><description>&lt;p&gt;Every now and again, I need use a global temporary table for some testing or demo code.&lt;/p&gt;
&lt;p&gt;Each time I do, I stumble a little bit when it comes to checking for the existence of the global temp table, in order to make my code re-runnable.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Duck_drop_table_sql_workbooks_global_temp_table-e1493397833690.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="check-for-global-temp-table-object-id"&gt;Check for Global Temp Table Object ID&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the TSQL to check for the object_id of a global temporary table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb..##Temp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="drop-global-temp-table-if-it-exists"&gt;Drop Global Temp Table If It Exists&lt;/h2&gt;
&lt;p&gt;So if you&amp;rsquo;d like to drop the global temp table if it exists, you can do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb..##Temp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;##&lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="truncate-or-create-global-temp-table"&gt;Truncate or Create Global Temp Table&lt;/h2&gt;
&lt;p&gt;Or if you&amp;rsquo;d like to truncate it if it exists, and create it if it doesn&amp;rsquo;t exist, you can do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb..##Temp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRUNCATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;##&lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;##&lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RecordID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CharColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pk_UserDatabaseTablePK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RecordID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Use Report View in Perfmon to Compare Database Counters (free video)</title><link>https://kendralittle.com/2017/05/01/use-report-view-in-perfmon-to-compare-database-counters-free-video/</link><pubDate>Mon, 01 May 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/05/01/use-report-view-in-perfmon-to-compare-database-counters-free-video/</guid><description>&lt;p&gt;Sometimes you need to compare lots of counters at once - for example, counters that report at the database level. This can be frustrating in &amp;ldquo;Line&amp;rdquo; view, but the &amp;ldquo;Report&amp;rdquo; view in perfmon makes life much simpler.&lt;/p&gt;
&lt;h2 id="video-tutorial"&gt;Video Tutorial&lt;/h2&gt;
&lt;p&gt;In this four minute video, I show you how to easily compare samples:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Mp-UDZzMxmE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>How Does a DBA Build Confidence After Making Mistakes? (Dear SQL DBA Episode 40)</title><link>https://kendralittle.com/2017/04/27/how-does-a-dba-build-confidence-after-making-mistakes-dear-sql-dba-episode-40/</link><pubDate>Thu, 27 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/27/how-does-a-dba-build-confidence-after-making-mistakes-dear-sql-dba-episode-40/</guid><description>&lt;p&gt;Ever had a database change go horribly wrong? It can feel awful in the moment, then eat away at your confidence for days afterward.&lt;/p&gt;
&lt;p&gt;In this 20 minute episode, I give you practical steps that help you cope with change over the course of your DBA career.&lt;/p&gt;
&lt;h2 id="video"&gt;Video&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/aKQWoNJ3jPw?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Error 1204: When SQL Server Runs Out of Locks</title><link>https://kendralittle.com/2017/04/26/error-1204-when-sql-server-runs-out-of-locks/</link><pubDate>Wed, 26 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/26/error-1204-when-sql-server-runs-out-of-locks/</guid><description>&lt;p&gt;I recently did a Dear SQL DBA episode answering a question about &lt;a href="https://www.youtube.com/watch?v=NaYSgh0uwG8"&gt;lock timeouts and memory&lt;/a&gt; in SQL Server. I really enjoyed the episode, and thought it would be fun to follow up and show what it looks like if SQL Server doesn&amp;rsquo;t have enough memory to allocate locks.&lt;/p&gt;
&lt;p&gt;You can control how much memory SQL Server allocates for locks using the &lt;a href="https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-locks-server-configuration-option"&gt;&amp;ldquo;locks&amp;rdquo; configuration option&lt;/a&gt;. At least for now: the configuration option is deprecated.&lt;/p&gt;
&lt;p&gt;Microsoft recommends that you do NOT change this setting, and let SQL Server manage your locks dynamically.&lt;/p&gt;
&lt;p&gt;I agree with them. Don&amp;rsquo;t mess around with the locks setting.&lt;/p&gt;
&lt;p&gt;That being said&amp;hellip;&lt;/p&gt;
&lt;h2 id="lets-do-some-bad-things-to-my-test-instance"&gt;Let&amp;rsquo;s do some bad things to my test instance!&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m going to change the lock configuration setting so that my SQL Server runs out of memory for locks pretty easily. Here&amp;rsquo;s my formula for lock memory starvation, using the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters sample database&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set the &amp;rsquo;locks&amp;rsquo; configuration to 5,000&lt;/li&gt;
&lt;li&gt;Restart the SQL Server service to make this (very bad) setting go into effect&lt;/li&gt;
&lt;li&gt;Disable lock escalation on a table with 104K rows: ALTER TABLE Sales.OrderLines SET (LOCK_ESCALATION = DISABLE)&lt;/li&gt;
&lt;li&gt;I run a query that&amp;rsquo;s greedy about locks&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="heres-my-greedy-lock-query"&gt;Here&amp;rsquo;s my greedy lock query&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OrderLineID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HOLDLOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROWLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The HOLDLOCK hint tells SQL Server to run in serializable mode for this table. That makes it &amp;ldquo;hold&amp;rdquo; locks for the life of the transaction &amp;ndash; not just take out and release locks as it rolls through the table.&lt;/p&gt;
&lt;p&gt;The ROWLOCK hint tells SQL Server to use the most granular form of locks. SQL Server would &amp;ldquo;escalate&amp;rdquo; these locks to the table level so that it wasn&amp;rsquo;t so granular, but we disallowed that as part of our lock starvation formula.&lt;/p&gt;
&lt;h2 id="error-message-1204-cannot-obtain-a-lock-resource"&gt;Error message 1204: cannot obtain a LOCK resource&lt;/h2&gt;
&lt;p&gt;My instance manages to stream 4837 rows back to me before it fails with this error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 1204, Level 19, State 4, Line 8
The instance of the SQL Server Database Engine cannot obtain a LOCK resource at this time.
Rerun your statement when there are fewer active users.
Ask the database administrator to check the lock and memory configuration for this instance, or to check for long-running transactions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The message comes back to my session. The message is also in the SQL Server error log, with my session_id as the source. And the message is written to the Windows Event Log under Application, too, where it shows as an error.&lt;/p&gt;
&lt;p&gt;In my case, though, the problem isn&amp;rsquo;t that I have too many active users, as the error message suggests. Or even that I don&amp;rsquo;t have enough memory.&lt;/p&gt;
&lt;h2 id="things-to-checkif-you-hit-this-error"&gt;Things to check if you hit this error&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Has anyone changed the locks configuration on your instance? (The default setting is 0)&lt;/li&gt;
&lt;li&gt;Have you disabled lock escalation on any tables?&lt;/li&gt;
&lt;li&gt;Does your code use ROWLOCK hints to force granular locks in the time periods where this is happening?&lt;/li&gt;
&lt;li&gt;Does the SQL Server instance have enough memory, and is it under memory pressure? This error will be thrown if &lt;a href="https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-locks-server-configuration-option"&gt;locks require 60% of engine memory, or memory is running short in Windows&lt;/a&gt; &amp;ndash; both of which are pretty dire circumstances for your instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As for me, I&amp;rsquo;m going to set the &amp;rsquo;locks&amp;rsquo; setting back to 0, restart my instance, and pretend this never happened.&lt;/p&gt;</description></item><item><title>Run perfmon.exe /sys to Remember Your Counters in Windows Perfmon (free video)</title><link>https://kendralittle.com/2017/04/24/run-perfmon-exe-sys-to-remember-your-counters-in-windows-perfmon-free-video/</link><pubDate>Mon, 24 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/24/run-perfmon-exe-sys-to-remember-your-counters-in-windows-perfmon-free-video/</guid><description>&lt;p&gt;The problem: by default, the Performance Monitor application in Windows doesn&amp;rsquo;t remember which counters you like to use.&lt;/p&gt;
&lt;p&gt;This can mean a lot of clicking every single time you open perfmon.&lt;/p&gt;
&lt;h2 id="the-easy-solution"&gt;The easy solution&lt;/h2&gt;
&lt;p&gt;Run: perfmon.exe /sys&lt;/p&gt;
&lt;p&gt;This makes perfmon remember the counters and configuration that you like to use!&lt;/p&gt;
&lt;p&gt;Watch this 2.5 minute video to see how the magic happens:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/zZA8IFfSKxQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Are Bad Statistics Making My Query Slow? (Dear SQL DBA Episode 39)</title><link>https://kendralittle.com/2017/04/20/are-bad-statistics-making-my-query-slow-dear-sql-dba-episode-39/</link><pubDate>Thu, 20 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/20/are-bad-statistics-making-my-query-slow-dear-sql-dba-episode-39/</guid><description>&lt;p&gt;An important query is suddenly slow. Is it because statistics are out of date? This is tricky to figure out, and updating statistics right away can make troubleshooting even harder. Learn how to use query execution plans to get to the heart of the question and find out if stats are really your problem, or if it&amp;rsquo;s something else.&lt;/p&gt;
&lt;p&gt;In this 35 minute episode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:39 SQL Server 2017 Announced&lt;/li&gt;
&lt;li&gt;01:10 New video from Microsoft&amp;rsquo;s Joe Sack demonstrating Adaptive Query Processing&lt;/li&gt;
&lt;li&gt;03:05 This week&amp;rsquo;s question: Are bad stats making my query slow?&lt;/li&gt;
&lt;li&gt;05:26 Demo of finding plan in cache and analyzing stats begins&lt;/li&gt;
&lt;li&gt;28:17 What to do when stats ARE the problem&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Code samples are at the bottom of the page&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="audio-only-version-downloadable"&gt;Audio-only version (downloadable)&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://dearsqldba.libsyn.com/site/are-bad-statistics-making-my-query-slow"&gt;Head to the episode home page for this&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="video-version"&gt;Video version&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Nks6LTaexSo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="related-links"&gt;Related links&lt;/h2&gt;
&lt;p&gt;SQL Server 2017 Adaptive Query Processing &lt;a href="https://www.youtube.com/watch?v=szTmo6rTUjM&amp;amp;feature=youtu.be"&gt;video by Joe Sack&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Michael J Swart on &lt;a href="http://michaeljswart.com/2017/04/finding-your-dark-queries/"&gt;finding Dark Matter Queries&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Slow in the Application, Fast in SSMS? &lt;a href="http://www.sommarskog.se/query-plan-mysteries.html"&gt;An SQL text by Erland Sommarskog&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="code-samples"&gt;Code samples&lt;/h2&gt;
&lt;script src="https://gist.github.com/LitKnd/f07848d59cedc61fd057d12ab966f703.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/f07848d59cedc61fd057d12ab966f703"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>Trace Flag 4199: No Per-Session Override if You Enable it Globally</title><link>https://kendralittle.com/2017/04/19/trace-flag-4199-no-per-session-override-if-you-enable-it-globally/</link><pubDate>Wed, 19 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/19/trace-flag-4199-no-per-session-override-if-you-enable-it-globally/</guid><description>&lt;p&gt;You can enable and disable trace flags either globally or per-session in SQL Server.&lt;/p&gt;
&lt;p&gt;This makes it seem like perhaps if you enable optimization trace flag 4199 globally for all sessions, you might be able to disable it per-session.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s NOT how it works.&lt;/p&gt;
&lt;h2 id="the-first-clue-is-in-dbcc-tracestatus"&gt;The first clue is in DBCC TRACESTATUS&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the code that enables Trace Flag 4199 globally on my instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4199&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can confirm that the trace flag is enabled with this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACESTATUS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbcc-tracestatus.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Enabling the trace flag globally doesn&amp;rsquo;t change my &amp;ldquo;Session&amp;rdquo; setting. Technically the trace flag isn&amp;rsquo;t enabled for my session&amp;ndash; but it&amp;rsquo;s going to be enabled for me because it&amp;rsquo;s enabled globally.&lt;/p&gt;
&lt;h2 id="running-dbcc-traceoff-for-my-session-doesnt-change-the-status"&gt;Running DBCC TRACEOFF for my session doesn&amp;rsquo;t change the status&lt;/h2&gt;
&lt;p&gt;I can try disabling the trace flag for my session with this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACEOFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4199&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I haven&amp;rsquo;t put the -1 in there, so I&amp;rsquo;m  just disabling this for my session.&lt;/p&gt;
&lt;p&gt;But no matter how many times I run this, the output from DBCC TRACESTATUS remains the same: the flag is enabled globally, and not enabled for my session.&lt;/p&gt;
&lt;h2 id="the-only-way-to-turn-this-off-is-to-turn-it-off-globally"&gt;The only way to turn this off is to turn it off globally&lt;/h2&gt;
&lt;p&gt;If I want to see how my queries optimize without trace flag 4199, I can disable it globally&amp;ndash; but this impacts every query running against the instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACEOFF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4199&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="sql-server-2016-makes-this-easier-to-work-with-by-providing-database-scoped-query-optimizer-hotfixes"&gt;SQL Server 2016 makes this easier to work with by providing database scoped Query Optimizer Hotfixes&lt;/h2&gt;
&lt;p&gt;In SQL Server 2016, you can now enable the very same optimizer hotfixes controlled by Trace Flag 4199 at the database scope by using ALTER DATABASE SCOPED CONFIGURATION SET QUERY_OPTIMIZER_HOTFIXES=ON.&lt;/p&gt;
&lt;p&gt;If you have the setting configured at the database level, it&amp;rsquo;s much easier to test what would happen if the setting was NOT enabled, because &lt;a href="https://kendralittle.com/2017/04/05/selectively-enabletrace-flag-4199-and-query_optimizer_hotfixes-in-sql-server-2016/"&gt;you can compile your query from a different database&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="want-to-prove-it-to-yourself-heres-some-demo-code"&gt;Want to prove it to yourself? Here&amp;rsquo;s some demo code&lt;/h2&gt;
&lt;p&gt;I set up a repro for a bug fixed by Trace Flag  4199 / QUERY_OPTIMIZER_HOTFIXES for SQL Server 2016. Here&amp;rsquo;s code you can run to prove to yourself that if 4199 is enabled globally, you can&amp;rsquo;t disable it for your session: &lt;a href="https://gist.github.com/LitKnd/612f6de6fb2bbc31100ee6f45df19d04"&gt;https://gist.github.com/LitKnd/612f6de6fb2bbc31100ee6f45df19d04&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Index Maintenance and Performance (Dear SQL DBA Episode 38)</title><link>https://kendralittle.com/2017/04/13/index-maintenance-and-performance-dear-sql-dba-episode-38/</link><pubDate>Thu, 13 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/13/index-maintenance-and-performance-dear-sql-dba-episode-38/</guid><description>&lt;p&gt;They made their index maintenance job smarter, and their queries got slower in production afterward. Could the index maintenance have harmed performance?&lt;/p&gt;
&lt;p&gt;In this 29 minute episode&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:50 Thinking about plan freezing in Query Store and multi-team process&lt;/li&gt;
&lt;li&gt;03:15 This week&amp;rsquo;s question about index maintenance and query performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subscribe to my &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube channel&lt;/a&gt;, or check out the audio &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast&lt;/a&gt; to listen anywhere, anytime. Links from this episode are in this post below the video and in the YouTube description.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/-xKEtZCKjdc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="links-and-further-reading-from-the-show-this-week"&gt;Links and further reading from the show this week&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Free, configurable index maintenance options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html"&gt;https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://minionware.net/reindex"&gt;http://minionware.net/reindex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may enjoy reading&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An interesting post on &lt;a href="https://sqlperformance.com/2016/07/sql-statistics/trace-flag-2389-new-cardinality-estimator"&gt;Trace Flag 2389 (ascending statistics flag) and the new cardinality estimator&lt;/a&gt;, by Erin Stellato&lt;/li&gt;
&lt;li&gt;The documentation on &lt;a href="https://support.microsoft.com/en-us/help/2754171/controlling-autostat-auto-update-statistics-behavior-in-sql-server"&gt;Trace Flag 2371 (changing automatic stats update behavior)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;My post on &lt;a href="https://kendralittle.com/2016/04/18/updating-statistics-in-sql-server-maintenance-answers/"&gt;Updating Statistics in SQL Server: Maintenance Questions &amp;amp; Answers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Will Optimize for Adhoc Workloads Save Memory?</title><link>https://kendralittle.com/2017/04/12/will-optimize-for-adhoc-workloads-save-memory/</link><pubDate>Wed, 12 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/12/will-optimize-for-adhoc-workloads-save-memory/</guid><description>&lt;p&gt;A while back, I got a question about enabling SQL Server&amp;rsquo;s &amp;lsquo;&lt;a href="https://msdn.microsoft.com/en-us/library/cc645587.aspx"&gt;Optimize for Adhoc Workloads&lt;/a&gt;&amp;rsquo; setting. The gist of the question was whether or not enabling this setting might free up extra memory on their SQL Server instance.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/best-laid-plans-e1490893102610.png"&gt;
&lt;/figure&gt;
&lt;h2 id="i-dont-get-excited-about-the-optimize-for-adhoc-workloads-setting-anymore"&gt;I don&amp;rsquo;t get excited about the &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo; setting anymore&lt;/h2&gt;
&lt;p&gt;Once upon a time, I was really excited about getting this configuration item in SQL Server 2008. Early versions of SQL Server 2005 weren&amp;rsquo;t all that great at managing the size of the execution plan cache: it could really balloon up and eat away at the buffer pool. But the SQL Server team did a good job at tuning those algorithms in later service packs for 2005 and future versions, and it became much less of an issue.&lt;/p&gt;
&lt;p&gt;Personally, I&amp;rsquo;ve never had a case where enabling &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo; improved performance in a way that I could measure. It may save you a small amount of memory, it may not.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t mean this as a big insult. Trying to save a penny every time you go to the grocery store could add up, if you grocery shop &lt;em&gt;very&lt;/em&gt; frequently. But hopefully that&amp;rsquo;s not one of your major revenue sources over time.&lt;/p&gt;
&lt;h2 id="what-does-optimize-for-adhoc-do"&gt;What does &amp;lsquo;Optimize for Adhoc&amp;rsquo; do?&lt;/h2&gt;
&lt;p&gt;Enabling this setting means that the first time a query runs, SQL Server will just store a small &amp;ldquo;stub&amp;rdquo; for the query&amp;rsquo;s execution plan. The second time that query runs, it will store the full plan in cache. So it essentially saves you &lt;em&gt;some&lt;/em&gt; (not all) of the memory for query plans that aren&amp;rsquo;t re-used.&lt;/p&gt;
&lt;h2 id="how-do-i-know-if-its-on"&gt;How do I know if it&amp;rsquo;s on?&lt;/h2&gt;
&lt;p&gt;This query looks at your current settings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configurations&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;optimize for ad hoc workloads&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the &amp;lsquo;value_in_use&amp;rsquo; column is set to 1, the setting is enabled on  your instance. If 0, it is not enabled.&lt;/p&gt;
&lt;h2 id="how-much-memory-would-this-save-me"&gt;How much memory would this save me?&lt;/h2&gt;
&lt;p&gt;Since the benefit here is to not store full execution plans that are only used once, check how many single-use execution plans are in memory after your instance has been up and running for a while to estimate the memory it might save you.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a simple query to estimate this from sys.dm_exec_cached_plans:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Size of single use adhoc plans in execution plan cache */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cacheobjtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_in_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_cached_plans&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usecounts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objtype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Adhoc&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cacheobjtype&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you see a high number here, I wouldn&amp;rsquo;t just enable &amp;lsquo;Optimize for Adhoc&amp;rsquo; and call it a day. Instead, I want to see some samples of what those single  use queries are, because&amp;hellip;&lt;/p&gt;
&lt;h2 id="there-may-be-a-better-fix"&gt;There may be a better fix!&lt;/h2&gt;
&lt;p&gt;My biggest issue with &amp;lsquo;Optimize for Adhoc&amp;rsquo; is that it might cause you to sweep some problems under the rug that wouldn&amp;rsquo;t be too tricky to resolve in a better way.&lt;/p&gt;
&lt;p&gt;If you have a lot of single use plans, look at what the queries actually are that are generating all these plans! Many times I have found them to come from a single application or job where someone used dynamic SQL and just never thought about parameterizing the code it generated. Parameterizing the code can be a better fix long term and allow plan reuse. (As with anything, test, because plan reuse is not always faster.)&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a simple query to explore what those single-use plans are, by joining to sys.dm_exec_sql_text:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cacheobjtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size_in_bytes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_cached_plans&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_sql_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan_handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usecounts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objtype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Adhoc&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: If you've got a large plan cache, this query might take a while. I've got a TOP 100 and an order by in the query just to keep it from returning more rows to SSMS than you can practically review. Consider removing the order by to see a quick sample (but similar queries may not be near one another, of course).
&lt;/div&gt;
&lt;h2 id="how-many-of-those-stubs-do-i-have-in-cache"&gt;How many of those stubs do I have in cache?&lt;/h2&gt;
&lt;p&gt;If you have this setting enabled, you can see the plan stubs in memory. Here&amp;rsquo;s a query that puts those plan stubs into the context of your whole execution plan cache:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cacheobjtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usecounts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Single&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Plans&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usecounts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size_in_bytes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Single&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Plans&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT_BIG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;All&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Plans&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_in_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;All&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Plans&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_cached_plans&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cacheobjtype&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="can-optimize-for-adhoc-workloads-slow-down-my-server"&gt;Can &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo; slow down my server?&lt;/h2&gt;
&lt;p&gt;I had one case where enabling &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo; caused a very measurable performance degradation&amp;ndash; not an outage, but a lot of slowness.&lt;/p&gt;
&lt;p&gt;This problem occurred on an instance with a very high transaction rate. The instance hit a bug in memory management in SQL Server 2008R2 that only occurred when &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo; was enabled.  Luckily you can enable and disable this setting with SQL Server online. When we did so, we could see processing rates speed up when we disabled the setting, and slow down when we enabled it. We could also measure the difference in SQL Server wait stats (specifically, CMEMTHREAD waits showed up when it was enabled).&lt;/p&gt;
&lt;p&gt;That bug has been fixed and it was definitely an edge case.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t to say I&amp;rsquo;d never use &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo;. Not at all. Potentially I might find a case someday where it does make a measurable difference and it&amp;rsquo;s the best option for some reason.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;No configuration&lt;/em&gt; is completely &amp;ldquo;safe&amp;rdquo; all the time, even well documented and often used configurations. Following best practices unfortunately doesn&amp;rsquo;t mean  you can&amp;rsquo;t hit bugs.&lt;/p&gt;
&lt;h2 id="how-to-enable-and-disable-the-setting"&gt;How to enable and disable the setting&lt;/h2&gt;
&lt;p&gt;You can manage this setting easily with TSQL. Changing this configuration item doesn&amp;rsquo;t require a SQL Server restart.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* First check if you have any pending configurations.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;Running RECONFIGURE will put all pending items into effect! */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configurations&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value_in_use&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* If everything looks OK, continue */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Enable advanced options */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;show advanced options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This enables optimize for adhoc. Set to 0 to disable.*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp_configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;optimize for ad hoc workloads&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RECONFIGURE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="should-optimize-for-adhoc-be-part-of-your-standard-configuration"&gt;Should &amp;lsquo;Optimize for Adhoc&amp;rsquo; be part of your standard configuration?&lt;/h2&gt;
&lt;p&gt;Arguing about this setting is a lot like arguing about whether or not it&amp;rsquo;s better to put cream in your coffee: if the coffee is decent, it probably tastes fine either way.&lt;/p&gt;
&lt;p&gt;My general preference is to not turn on a setting unless I have a good reason to believe that it will make a positive difference, so I don&amp;rsquo;t turn this on by default. Instead, I&amp;rsquo;d rather monitor the number of single use plans in cache, and investigate and act accordingly if that number starts spiking upwards.&lt;/p&gt;
&lt;p&gt;But admittedly, that&amp;rsquo;s being fussy: if I had a flock of 1,000 SQL Servers to manage myself and I knew they were all patched to recent supported versions, I&amp;rsquo;d probably enable it on them all and I wouldn&amp;rsquo;t feel a bit bad about it, because I wouldn&amp;rsquo;t have the bandwidth to do it the very best, artisanal, hand-crafted way.&lt;/p&gt;</description></item><item><title>Poster in the works: SSMS Shortcuts Explained by Cats</title><link>https://kendralittle.com/2017/04/10/poster-in-the-works-ssms-shortcuts-explained-by-cats/</link><pubDate>Mon, 10 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/10/poster-in-the-works-ssms-shortcuts-explained-by-cats/</guid><description>&lt;p&gt;I had a fun &lt;a href="https://kendralittle.com/2017/04/03/reviving-healthy-work-habits-toggl-and-weekly-highlights/"&gt;highlight&lt;/a&gt; recently that I wanted to share. I&amp;rsquo;ve got a new poster idea I&amp;rsquo;m crazy about.&lt;/p&gt;
&lt;h2 id="sql-server-management-studio-shortcuts-explained-by-cats"&gt;SQL Server Management Studio Shortcuts, Explained by Cats&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m working through this iteratively: I&amp;rsquo;m doing drawings for select lessons in my free course, &lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;SSMS Shortcuts &amp;amp; Secrets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the first two that I&amp;rsquo;ve done:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ssms-shortcuts-new-session-use-database-execute-query-show-hide-results.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Creating new sessions and executing queries&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/ssms-shortcuts-indent-comment.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Indenting TSQL, Commenting and Un-Commenting TSQL. I got the mnemonic for CTRL-K + CTRL-C from &lt;a href="https://twitter.com/onupdatecascade"&gt;@onupdatecascade&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When I get a bunch of them done, I&amp;rsquo;ll combine them into a poster and set that up for download.&lt;/p&gt;
&lt;p&gt;While I love drawing, it&amp;rsquo;s pretty time consuming, and it&amp;rsquo;s not easy. Each of these drawings took me more than an hour. And I only seem to be able to draw if I&amp;rsquo;m really into an idea, otherwise it turns out as a big angry scribble. (This is why I could never be a professional artist, and really admire people who do it.)  So when I have an idea I really like, and I&amp;rsquo;m actually able to start executing on it, that&amp;rsquo;s a big old weekly highlight.&lt;/p&gt;</description></item><item><title>Lock Timeouts &amp; Memory (Dear SQL DBA Episode 37)</title><link>https://kendralittle.com/2017/04/06/lock-timeouts-memory-dear-sql-dba-episode-36/</link><pubDate>Thu, 06 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/06/lock-timeouts-memory-dear-sql-dba-episode-36/</guid><description>&lt;p&gt;The dev server got bogged down during a deployment and lock timeouts were everywhere. Was the perfmon counter way off about how much memory was being used just for locks?&lt;/p&gt;
&lt;h2 id="episode-contents"&gt;Episode Contents&lt;/h2&gt;
&lt;p&gt;In this 19 minute episode&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:33 What&amp;rsquo;s new @ SQL Workbooks: Down the Rabbit Hole&lt;/li&gt;
&lt;li&gt;03:00 This week&amp;rsquo;s question about lock timeouts &amp;amp; memory in SQL Server&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="subscribe"&gt;Subscribe&lt;/h2&gt;
&lt;p&gt;Subscribe to Dear SQL DBA on &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube&lt;/a&gt;, or check out the audio &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast&lt;/a&gt; to listen anywhere, anytime.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: It does say Episode #36 at the beginning of the video, but this is really episode #37. Oops.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/NaYSgh0uwG8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Selectively EnableTrace Flag 4199 and QUERY_OPTIMIZER_HOTFIXES in SQL Server 2016</title><link>https://kendralittle.com/2017/04/05/selectively-enabletrace-flag-4199-and-query_optimizer_hotfixes-in-sql-server-2016/</link><pubDate>Wed, 05 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/05/selectively-enabletrace-flag-4199-and-query_optimizer_hotfixes-in-sql-server-2016/</guid><description>&lt;p&gt;Trace Flag 4199 has been in SQL Server for a while. I&amp;rsquo;ve long thought of this as the &amp;ldquo;Bucket of Optimizer Hotfixes&amp;rdquo; trace flag: enabling it turns on a variety of hotfixes that have been implemented over the years.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/scope.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;When query tuning, I&amp;rsquo;ve often tested whether or not Trace Flag 4199 makes a difference to the query I&amp;rsquo;m tuning. Most of the time it doesn&amp;rsquo;t make a difference. I&amp;rsquo;ve had some rare occasions where it&amp;rsquo;s made a query faster. I&amp;rsquo;ve never personally found a case where enabling the flag slowed a query down.&lt;/p&gt;
&lt;h2 id="past-trace-flag-4199-fixes-go-mainstream-in-sql-server-2016-with-compatibility-level-130"&gt;Past Trace Flag 4199 fixes go mainstream in SQL Server 2016 with compatibility level 130&lt;/h2&gt;
&lt;p&gt;One of the weird thing about the fixes under 4199 was that they never used to get merged into the mainstream codebase. The amount of things changed by the flag just kept growing. This was fixed in SQL Server 2016. If you&amp;rsquo;re using database compatibility level 130, all the fixes for prior SQL Server versions are enabled, and the optimizer will use them.&lt;/p&gt;
&lt;p&gt;I think this is a great thing. Merging in those fixes makes understanding what 4199 does much less confusing &amp;ndash; and Trace Flag 4199 is still being used for new fixes, too!&lt;/p&gt;
&lt;h2 id="implementing-trace-flags-for-optimizer-hotfixes-has-always-been-a-bit-klunky"&gt;Implementing Trace Flags for optimizer hotfixes has always been a bit klunky&lt;/h2&gt;
&lt;p&gt;Trace Flag 4199 has a bit of baggage when  it comes to implementation. Prior to SQL Server 2016, if you wanted to enable these optimizer hotfixes, you have three choices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can implement the trace flag globally, for the whole instance as a startup flag, or using DBCC TRACEON with -1. But that seems like overkill if you only have one query that needs the trace flag, and the trace flag implements a whole bunch of changes.&lt;/li&gt;
&lt;li&gt;You can implement the trace flag for a single session, using DBCC TRACEON without the -1. You&amp;rsquo;ve got to be really careful if you do this and use session pooling, and running DBCC TRACEON requires sysadmin permissions, so this is rarely used in production code.&lt;/li&gt;
&lt;li&gt;You can implement the trace flag for a single query using OPTION QUERYTRACEON, but there are some permission issues. If this is running as an adhoc query, it requires sysadmin permissions. There is a workaround where you can use it &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/1619568/querytraceon-with-no-additional-permissions"&gt;with lower permission in a stored procedure, but that doesn&amp;rsquo;t work for every application&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="new-database-scoped-option-for-query-optimizer-hotfixes"&gt;New database scoped option for Query Optimizer Hotfixes&lt;/h2&gt;
&lt;p&gt;In SQL Server 2016 RTM, we got the option to enable Query Optimizer Hotfixes for a given database. This is great to have a finer-grained scope. You enable this for a database with the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCOPED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CONFIGURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERY_OPTIMIZER_HOTFIXES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="new-use-hint-option-for-query-optimizer-hotfixes-and-more"&gt;New &amp;lsquo;USE HINT&amp;rsquo; option for  Query Optimizer Hotfixes (and more)&lt;/h2&gt;
&lt;p&gt;Even better, in SQL Server 2016 SP1, we got the option to enable this for a given query in a hint, with code like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* No sort here -- works same as DB setting (makes sense) */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IntCol&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LetsTalkAboutQueryOptimizerHotfixes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PartitioningCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2017-10-02&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PartitioningCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CharCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ENABLE_QUERY_OPTIMIZER_HOTFIXES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gets around that pesky high-permissions problem that the QUERYTRACEON hint uses. A couple of things to keep in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;USE HINT can be used for more than just Query Optimizer Hotfixes. There&amp;rsquo;s a list in the &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-query"&gt;documentation on hints&lt;/a&gt;, and you can also query them from the sys.dm_exec_valid_use_hints DMV.&lt;/li&gt;
&lt;li&gt;HINT names are case sensitive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-if-i-enable-query-optimizer-hotfixes-at-thedatabase-level-and-want-to-test-how-a-query-would-run-if-it-was-turned-off"&gt;What if I enable Query Optimizer Hotfixes at the database level, and want to test how a query would run if it was turned off?&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say I have a few queries that get a performance boost from query optimizer hotfixes on SQL Server 2016. For whatever reason, I don&amp;rsquo;t choose the USE HINT route&amp;ndash; I enable Query Optimizer Hotfixes at the database level.&lt;/p&gt;
&lt;p&gt;Things are going fine, but when I&amp;rsquo;m tuning a slow query in that database, I wonder&amp;ndash; would I get a different plan if I didn&amp;rsquo;t have Query Optimizer Hotfixes on?&lt;/p&gt;
&lt;p&gt;But there isn&amp;rsquo;t a USE HINT option to disable query optimizer hotfixes just for my query.&lt;/p&gt;
&lt;h2 id="simple-fix-for-testing-just-compile-your-query-from-another-database"&gt;Simple fix for testing: just compile your query from another database!&lt;/h2&gt;
&lt;p&gt;I have &lt;a href="https://facility9.com/"&gt;Jeremiah Peschka&lt;/a&gt; to thank for this simple solution: just use tempdb and compile your query against your database with three part names.&lt;/p&gt;
&lt;p&gt;Since Query Optimizer Hotfxes is scoped to the database, using another database where the setting isn&amp;rsquo;t on to compile your query gives you a totally different plan, compiled with that database&amp;rsquo;s settings for query optimizer hotfixes.&lt;/p&gt;
&lt;h2 id="want-to-play-around-with-it-heres-a-some-repro-code"&gt;Want to play around with it? Here&amp;rsquo;s a some repro code!&lt;/h2&gt;
&lt;p&gt;To make sure this was as good as it sounded, I set up a repro for &lt;a href="https://support.microsoft.com/en-us/help/3198775/fix-an-inefficient-query-plan-is-used-for-a-query-requiring-order-by-partitioning-column-of-a-table-with-single-partition"&gt;a bug fixed after SQL Server 2016 RTM&lt;/a&gt; which requires enabling TF4199 or QUERY_OPTIMIZER_HOTFIXES as part of the solution.&lt;/p&gt;
&lt;p&gt;This bug impacts partitioned tables that have only a single partition. The bug is that the optimizer inserts a SORT operator into the plan without realizing that the index it&amp;rsquo;s using provides the sorting.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve enabled QUERY_OPTIMIZER_HOTFIXES at the database level, and here&amp;rsquo;s how my query plan looks&amp;hellip; the bug is fixed:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-optimizer-hotfixes-no-bug.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;But what would my plan look like with Query Optimizer Hotfixes off? When I compile the query from tempdb (which doesn&amp;rsquo;t have the setting enabled) using three part naming, the bug is there and the plan has a SORT operator:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/query-optimizer-hotfixes-plan-seen-from-tempdb.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id="you-could-selectively-implement-or-test-query-optimizer-hotfixes-by-creating-stored-procedures-or-views-in-a-separate-database-from-the-tables-and-querying-them"&gt;You could selectively implement or test Query Optimizer Hotfixes by creating stored procedures or views in a separate database from the tables, and querying them&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you&amp;rsquo;ve got a very large database, and you want to do a side-by-side testing some code &amp;ndash; one version with query optimizer hotfixes on, one with it off. But the database is so large that restoring two copies isn&amp;rsquo;t so attractive.&lt;/p&gt;
&lt;p&gt;You can create a second, empty database, and create copies of your stored procedures or views that use three part names to access the tables in your primary database. Then you can enable or disable Query Optimizer hotfixes at the database scope in either database, and it&amp;rsquo;s easy to compare.&lt;/p&gt;
&lt;p&gt;I think this is mostly an interesting option for testing more than production code. That&amp;rsquo;s just because in production code, if you want to selectively implement this, then the USE HINT option seems simpler.&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s always nice to have options!&lt;/p&gt;
&lt;h2 id="want-to-play-around-with-this-yourself"&gt;Want to play around with this yourself?&lt;/h2&gt;
&lt;p&gt;Grab the code to repro these execution plans &lt;a href="https://gist.github.com/LitKnd/93a0a4ed4e15039ba0030e1bb34a74dd"&gt;from this Gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Remember that you need to be running SQL Server 2016 for this to work, and you need SP1 if you&amp;rsquo;d like to play around with OPTION (USE HINT (&amp;lsquo;ENABLE_QUERY_OPTIMIZER_HOTFIXES&amp;rsquo;)).&lt;/p&gt;</description></item><item><title>Reviving Healthy Work Habits: Toggl and Weekly Highlights</title><link>https://kendralittle.com/2017/04/03/reviving-healthy-work-habits-toggl-and-weekly-highlights/</link><pubDate>Mon, 03 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/03/reviving-healthy-work-habits-toggl-and-weekly-highlights/</guid><description>&lt;p&gt;As I&amp;rsquo;ve gotten back into the swing of a more-or-less regular work schedule after the initial launch of &lt;a href="https://kendralittle.com/coursesbytitle/"&gt;SQL Workbooks&lt;/a&gt;, I&amp;rsquo;ve revived some of my favorite work habits and free tools.&lt;/p&gt;
&lt;h2 id="tracking-time-with-toggl"&gt;Tracking time with Toggl&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/time-tracking-technology.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;m a big fan of the &lt;a href="https://toggl.com/"&gt;time-tracking tool Toggl&lt;/a&gt;.  Their tools are easy to use, and even the free version is very cool.&lt;/p&gt;
&lt;p&gt;Tracking time may seem like a giant pain if you&amp;rsquo;re used to using terrible tools for it. But Toggl is simple, and it helps keep me sane.&lt;/p&gt;
&lt;p&gt;I have a tendency to work a lot. I can really enjoy a long workday. The problem is that if I pull too many long workdays, I burn myself out. I stop walking my dog and skip workouts. I eat crummier food. My mood and health slide downhill.&lt;/p&gt;
&lt;p&gt;Tracking my time has two purposes for me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I learn how long things take, on average&lt;/li&gt;
&lt;li&gt;I can keep myself honest about how many hours I work every week&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like most people, I am &lt;em&gt;horrible&lt;/em&gt; at estimating how long things take. I&amp;rsquo;m even pretty bad at estimating how long I&amp;rsquo;ve been doing something! Toggl takes the mystery out of all this.&lt;/p&gt;
&lt;p&gt;These days, I work pretty weird hours. There&amp;rsquo;s lots of construction going on within shouting distance of my recording area, so I do video recording mostly after 5 pm or on Sundays. This works fine for me as long as I balance things out at other times, and Toggl helps me do just that.&lt;/p&gt;
&lt;p&gt;Next up: I&amp;rsquo;m going to start experimenting with Toggl&amp;rsquo;s built in Pomodoro timer this week. (My first week I just spent tracking, to make life simpler.)&lt;/p&gt;
&lt;h2 id="weekly-highlights"&gt;Weekly highlights&lt;/h2&gt;
&lt;p&gt;I once had a manager who asked me to write down a few highlights and lowlights each week. At first this was a bit of a drag, but after a while I grew to love it.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s two reasons to do weekly highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To build a sense of satisfaction in your work&lt;/li&gt;
&lt;li&gt;To figure out where you need to invest or ask for help to make thing easier&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oftentimes at the end of the week we are so happy to get to the weekend that we don&amp;rsquo;t think about what we did well. Writing down highlights helps you recognize your own achievements (which are &lt;a href="https://kendralittle.com/2017/03/20/time-for-an-interview-what-accomplishment-are-you-most-proud-of/"&gt;surprisingly easy to forget&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Lowlights are also useful. At first this feels like, &amp;ldquo;Where did you fail?&amp;rdquo; That&amp;rsquo;s not the point. Instead, it&amp;rsquo;s helpful to recognize where you had a hard time, because there may be ways to make that easier in the future. When something is a repeat lowlight, that gives you data about where it can be useful to change something.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extra bonus&lt;/strong&gt;: If you have any kind of annual review process, looking back at weekly highlights and lowlights is incredibly useful: you&amp;rsquo;ve got a bunch of data about what you contributed, and also about what you&amp;rsquo;d like to ask for.&lt;/p&gt;
&lt;p&gt;So make yourself a 10 minute calendar reminder to do highlights and lowlights each week.&lt;/p&gt;
&lt;p&gt;For me, Friday morning is a MUCH better time to do this than Friday afternoon, because I&amp;rsquo;m generally in a good mood and not hurried on Friday mornings. I use Google Keep and Google Calendar, so I&amp;rsquo;ve set myself a recurring weekly reminder for Friday morning in Google Keep.&lt;/p&gt;</description></item><item><title>Which Locks Count Toward Lock Escalation?</title><link>https://kendralittle.com/2017/04/03/which-locks-count-toward-lock-escalation/</link><pubDate>Mon, 03 Apr 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/04/03/which-locks-count-toward-lock-escalation/</guid><description>&lt;p&gt;A little while back I wrote about &lt;a href="https://kendralittle.com/2017/03/14/why-indexes-reduce-locks-for-update-and-delete-queries/"&gt;Why Indexes Reduce Locks for Update and Delete Queries&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I got a great question on the post from Zac:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What’s not super clear is why it takes out a lock on the whole table, is this because it does a lock escalation as a result of the Full Scan? Will this always happen, or is there a threshold of record update counts where this will occur?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was tough to answer in just a comment, so I promised a full post on the topic.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/lock-escalator.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="sql-server-attempts-lock-escalation-to-simplify-locks"&gt;SQL Server attempts lock escalation to simplify locks&lt;/h2&gt;
&lt;p&gt;It can be tricky to manage a lot of little fine grained locks. If I take out 50,000 row locks on a single table, it would be easier for SQL Server to manage that by just giving me one table level lock. But this may not be possible if others are using the table.&lt;/p&gt;
&lt;p&gt;When you take out a lot of modification locks, SQL Server will attempt to &amp;ldquo;escalate&amp;rdquo; them. If it can&amp;rsquo;t escalate and I keep taking out locks, it will keep trying.&lt;/p&gt;
&lt;p&gt;Books Online has a good article about this, which explains a lot of the details about how many locks you need to take out to &lt;a href="https://technet.microsoft.com/en-us/library/ms184286.aspx"&gt;trigger lock escalation&lt;/a&gt;. Here are the (simplified) basics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &amp;lsquo;magic&amp;rsquo; number to trigger escalation for the first time is 5,000 locks on a single table reference&lt;/li&gt;
&lt;li&gt;Locks do NOT escalate from row level to page level. Row locks escalate to table. Page level locks also escalate to table level. In other words, forcing row level locking will not make it less likely to escalate locks to the table level, but rather it will do the opposite.
&lt;ul&gt;
&lt;li&gt;Note: for partitioned tables, you have the option to enable partition level escalation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re modifying data, the escalated table lock will be exclusive. That means nobody else can party with the table if lock escalation succeeds while you&amp;rsquo;re doing your work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="but-which-locks-cause-escalation-all-those-update-locks-dont-cause-escalation-do-they"&gt;But which locks cause escalation? All those update locks don&amp;rsquo;t cause escalation, do they?&lt;/h2&gt;
&lt;p&gt;No, the update locks do NOT cause escalation. Just as a reminder, &amp;ldquo;update&amp;rdquo; locks are weirdly named&amp;ndash; these are a special kind of lock (not just a type of lock associated with an &amp;ldquo;update&amp;rdquo; statement). &lt;a href="https://kendralittle.com/2017/03/14/why-indexes-reduce-locks-for-update-and-delete-queries//"&gt;Read more in my post on update locks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at a simple test I ran on a VM to show update locks not triggering the &amp;ldquo;escalator&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters sample database&lt;/a&gt; again. To make sure I get the most update locks possible for my test, I dropped the index on CustomerID:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FK_Sales_Orders_CustomerID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This forces a clustered index scan on all the sample queries I&amp;rsquo;m going to run below.&lt;/p&gt;
&lt;h2 id="im-running-two-extended-events-traces"&gt;I&amp;rsquo;m running two Extended Events Traces&lt;/h2&gt;
&lt;p&gt;The first trace is looking at the sqlserver.lock_escalation event. Note that I&amp;rsquo;m using NO_EVENT_LOSS and MAX_DISPATCH_LATENCY=5 in this trace&amp;mdash; that&amp;rsquo;s because I&amp;rsquo;m running this against a totally private test instance, and it doesn&amp;rsquo;t matter if I impact performance.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LockEscalation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock_escalation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collect_database_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;collect_statement&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;S:\XEvents\Lock_Escalation.xel&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;NO_EVENT_LOSS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAX_EVENT_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MEMORY_PARTITION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRACK_CAUSALITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;STARTUP_STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second trace is counting the locks used used by session_id=56. It&amp;rsquo;s looking for locks against a particular object (I don&amp;rsquo;t care about metadata locks), and it&amp;rsquo;s putting the output in a histogram target bucketed by the lock mode:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;locks_count_spid_56&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock_acquired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;],(&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;associated_object_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;72057594047234048&lt;/span&gt;&lt;span class="p"&gt;.)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;histogram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filtering_event_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sqlserver.lock_acquired&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mode&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;source_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_MULTIPLE_EVENT_LOSS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAX_EVENT_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MEMORY_PARTITION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACK_CAUSALITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;STARTUP_STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/event-classes/lock-escalation-event-class"&gt;This article&lt;/a&gt; helps decode the integer that represents the lock mode in this trace.
&lt;/div&gt;
&lt;p&gt;Looking at this, I&amp;rsquo;m embarrassed by how inconsistent I am at naming traces. But I&amp;rsquo;m consistently bad at that, so&amp;hellip; yeah.&lt;/p&gt;
&lt;h2 id="test-query-1-modifiesonly-165-rows-no-lock-escalation"&gt;Test query #1 modifies only 165 rows, no lock escalation&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s our first contender&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hiya&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This does a clustered index scan, but modifies only 165 rows. I roll back the transaction just for further testing.&lt;/p&gt;
&lt;p&gt;What do the traces have to say?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The LockEscalation trace doesn&amp;rsquo;t say anything. We had NO lock escalation for this trace.&lt;/li&gt;
&lt;li&gt;The locks_count_spid_56 trace shows
&lt;ul&gt;
&lt;li&gt;104,184 update locks&lt;/li&gt;
&lt;li&gt;2,591 intent update locks&lt;/li&gt;
&lt;li&gt;165 exclusive locks&lt;/li&gt;
&lt;li&gt;153 intent exclusive locks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We had &lt;em&gt;way&lt;/em&gt; more than 5K update locks on this object, but they don&amp;rsquo;t count toward lock escalation.&lt;/p&gt;
&lt;h2 id="test-query-2-modifies4951-rows-and-does-escalate-locks"&gt;Test query #2 modifies 4,951 rows and DOES escalate locks&lt;/h2&gt;
&lt;p&gt;Before starting this test, I restarted my locks_count_spid_56 trace to reset it. Then I ran this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hoya&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1013&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This also does a clustered index scan, and modifies just &lt;em&gt;under&lt;/em&gt; 5,000 rows. So it would seem like this wouldn&amp;rsquo;t escalate. Let&amp;rsquo;s see!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The LockEscalation trace has a row! This escalated.
&lt;ul&gt;
&lt;li&gt;escalation_cause = Lock threshold&lt;/li&gt;
&lt;li&gt;escalated_lock_count (number of locks converted) = 6,248&lt;/li&gt;
&lt;li&gt;hobt_lock_count (number of locks at time of escalation) = 6,247&lt;/li&gt;
&lt;li&gt;The statement collected matches this query. (The recompile hint in the query is there to prevent auto-parameterization in this simple, so it&amp;rsquo;s very clear which query was run.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The locks_count_spid_56 trace shows
&lt;ul&gt;
&lt;li&gt;97,842 update locks&lt;/li&gt;
&lt;li&gt;2,340 intent update locks&lt;/li&gt;
&lt;li&gt;4,475 exclusive locks&lt;/li&gt;
&lt;li&gt;1,772 intent exclusive locks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="time-for-a-little-math"&gt;Time for a little math&lt;/h2&gt;
&lt;p&gt;4,475 exclusive locks + 1,772 intent exclusive locks = 6,247 locks at the time of escalation.&lt;/p&gt;
&lt;p&gt;The update and intent update locks don&amp;rsquo;t count toward escalation.&lt;/p&gt;
&lt;h2 id="what-does-this-all-mean"&gt;What does this all mean?&lt;/h2&gt;
&lt;p&gt;Good indexing can reduce the number of update locks that queries take out &amp;ndash; that can reduce blocking, because update locks block one another. And besides, good indexing can make queries faster.&lt;/p&gt;
&lt;p&gt;Lock escalation converts exclusive and intent exclusive locks. The initial threshold to trigger lock escalation is 5,000 locks used in a single table reference, but you might hit that threshold even if you&amp;rsquo;re modifying less than 5,000 rows.&lt;/p&gt;
&lt;p&gt;If you have to modify a lot of rows in a table that&amp;rsquo;s being used by others where performance matters, lock escalation is one of multiple factors that makes it desirable to break the modifications up into smaller transactions.&lt;/p&gt;
&lt;p&gt;Having lock escalation isn&amp;rsquo;t &lt;em&gt;necessarily&lt;/em&gt; a bad thing. If escalation succeeds, it&amp;rsquo;s possible that the query with escalated locks doesn&amp;rsquo;t end up blocking anyone else. You need to monitor the SQL Server to know whether or not you&amp;rsquo;ve got a blocking problem, and who is blocking whom.&lt;/p&gt;</description></item><item><title>Why is My Transaction Log Growing in My Availability Group? (Dear SQL DBA Episode 36)</title><link>https://kendralittle.com/2017/03/30/why-is-my-transaction-log-growing-in-my-availability-group-dear-sql-dba-episode-36/</link><pubDate>Thu, 30 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/30/why-is-my-transaction-log-growing-in-my-availability-group-dear-sql-dba-episode-36/</guid><description>&lt;p&gt;A database transaction log is expanding, even though the DBA is running log backups and doesn&amp;rsquo;t see an open transaction? What&amp;rsquo;s going on with this Availability Group?&lt;/p&gt;
&lt;p&gt;Links to timestamps in this 30 minute episode if you want to skip ahead&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/Iw7uhs807JA#t=00m49s"&gt;00:49&lt;/a&gt; What&amp;rsquo;s new @ SQL Workbooks&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/Iw7uhs807JA#t=03m22s"&gt;03:22&lt;/a&gt; Info on SQLPASS Summit 2017 Content Survey &amp;amp; a heads-up for aspiring precon speakers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/Iw7uhs807JA#t=05m35s"&gt;05:35&lt;/a&gt; This week&amp;rsquo;s question about t-log growth&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subscribe to my &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube channel&lt;/a&gt;, or check out the audio &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast&lt;/a&gt; to listen anywhere, anytime. Links from this episode are in this post below the video and in the YouTube description.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Iw7uhs807JA?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="links-from-this-weeks-episode"&gt;Links from this week&amp;rsquo;s episode&lt;/h2&gt;
&lt;p&gt;SQLPass Summit 2017 Content Survey (enter your email for a chance to win free registration): &lt;a href="https://www.surveymonkey.com/r/KFS2ZJW"&gt;https://www.surveymonkey.com/r/KFS2ZJW&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you are interested in submitting a pre-conference session for SQLPASS Summit 2017, fill out the form on Wendy&amp;rsquo;s blog post here: &lt;a href="http://www.pass.org/Community/PASSBlog/tabid/1476/entryid/839/Changes-to-the-PASS-Summit-2017-Program-Pre-Conference-Call-for-Interest-and-a-Community-Survey.aspx"&gt;http://www.pass.org/Community/PASSBlog/tabid/1476/entryid/839/Changes-to-the-PASS-Summit-2017-Program-Pre-Conference-Call-for-Interest-and-a-Community-Survey.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lazy log truncation (SQL Server PFE blog by Lisa Gardner) : &lt;a href="https://blogs.msdn.microsoft.com/sql_pfe_blog/2013/06/27/lazy-log-truncation-clearing-of-sql-transaction-log-vlf-status-deferred"&gt;https://blogs.msdn.microsoft.com/sql_pfe_blog/2013/06/27/lazy-log-truncation-clearing-of-sql-transaction-log-vlf-status-deferred&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;sys.dm_hadr_database_replica_states: &lt;a href="https://docs.microsoft.com/sql/relational-databases/system-dynamic-management-views/sys-dm-hadr-database-replica-states-transact-sql"&gt;https://docs.microsoft.com/sql/relational-databases/system-dynamic-management-views/sys-dm-hadr-database-replica-states-transact-sql&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chasing Ghost cleanup in Availability Groups (by Amit Banerjee): &lt;a href="https://troubleshootingsql.com/2014/07/25/chasing-the-ghost-cleanup-in-an-availability-group/"&gt;https://troubleshootingsql.com/2014/07/25/chasing-the-ghost-cleanup-in-an-availability-group/&lt;/a&gt;&lt;/p&gt;</description></item><item><title>The Case of the Blocking Online Index Create- the Shared Lock that Would Not Quit</title><link>https://kendralittle.com/2017/03/28/the-case-of-the-blocking-online-index-create-a-shared-lock-that-wouldnt-quit/</link><pubDate>Tue, 28 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/28/the-case-of-the-blocking-online-index-create-a-shared-lock-that-wouldnt-quit/</guid><description>&lt;p&gt;I recently got an interesting question from a reader about running a CREATE INDEX statement with DROP_EXISTING&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/create-index-with-drop-existing.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s the question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I always take advantage of creating/modifying nonclustered indexes online since we are running SQL Server 2014 Enterprise Edition. This weekend I ran into an issue while modifying an existing nonclustered index (added a new column to INCLUDE): I was blocking any write operations on the table. After digging into this issue, I noticed that there was a Shared lock on the table.&lt;/p&gt;
&lt;p&gt;From my knowledge, at the very beginning a shared lock needs to be acquired but it’s should be very fast one &amp;ndash; &lt;a href="https://msdn.microsoft.com/en-us/library/ms191261.aspx"&gt;https://msdn.microsoft.com/en-us/library/ms191261.aspx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I ran the index creation for more than an hour and had to kill it because it started to significantly affect clients. I just don’t understand why the shared lock would be held for such a long time.&lt;/p&gt;
&lt;p&gt;I can reproduce it on my test server with no activities on this database.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I thought this was a really interesting question, because our reader is correct: an online index creation statement should only need a shared lock, briefly, at the beginning of execution.&lt;/p&gt;
&lt;h2 id="ruling-out-the-simple-things-first-is-the-shared-lock-getting-blocked"&gt;Ruling out the simple things first: is the shared lock getting blocked?&lt;/h2&gt;
&lt;p&gt;My first thought was that perhaps there is some process that runs against the production system and the test system that goes to sleep with an open transaction, holding an X or an IX lock against this table. If the index create can&amp;rsquo;t get its shared lock, then it could be part of a blocking chain.&lt;/p&gt;
&lt;p&gt;So I asked first if the index create was the head of the blocking chain, or if it was perhaps blocked by something else. The answer came back that no, the index create was NOT blocked. It was holding the shared lock for a long time.&lt;/p&gt;
&lt;p&gt;My new friend even sent a screenshot of the index create running against the test instance in sp_WhoIsActive with blocking_session_id null.&lt;/p&gt;
&lt;h2 id="and-it-wasnt-just-one-shared-lock-it-was-120"&gt;And it wasn&amp;rsquo;t just one shared lock. It was 120!&lt;/h2&gt;
&lt;p&gt;To deepen the mystery, he ran sp_WhoIsActive with @get_locks=1,  and the locks for the running, non-blocked index create showed:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;Lock resource_type=&amp;#34;OBJECT&amp;#34; request_mode=&amp;#34;IS&amp;#34; request_status=&amp;#34;GRANT&amp;#34; request_count=&amp;#34;1&amp;#34; /&amp;gt;
&amp;lt;Lock resource_type=&amp;#34;OBJECT&amp;#34; request_mode=&amp;#34;S&amp;#34; request_status=&amp;#34;GRANT&amp;#34; request_count=&amp;#34;120&amp;#34; /&amp;gt;
&amp;lt;Lock resource_type=&amp;#34;OBJECT&amp;#34; request_mode=&amp;#34;Sch-S&amp;#34; request_status=&amp;#34;GRANT&amp;#34; request_count=&amp;#34;1&amp;#34; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Yep, that&amp;rsquo;s 120 OBJECT level shared locks, just hanging out while the online create is running.&lt;/p&gt;
&lt;p&gt;I was curious if the number 120 was meaningful to this table somehow. Were there 120 partitions? 120 indexes? 120 triggers? (I know it sounds weird, but I&amp;rsquo;ve found weirder.)&lt;/p&gt;
&lt;p&gt;Nope, there weren&amp;rsquo;t 120 of anything identifiable.&lt;/p&gt;
&lt;p&gt;We did a little tracing, and a little discussion in email. And just as soon as I sent an email that said, &amp;ldquo;I can&amp;rsquo;t reproduce this on SQL Server 2016 at all, I think you have a bug!&amp;rdquo; I got an email back that said, &amp;ldquo;This is a bug!&amp;rdquo;&lt;/p&gt;
&lt;h2 id="the-bugrebuilding-a-nonclustered-index-to-add-columns-by-using-create-index-with-drop_existingon-and-onlineon-causes-blocking-kb3194365"&gt;The bug: Rebuilding a nonclustered index to add columns by using CREATE INDEX with DROP_EXISTING=ON and ONLINE=ON causes blocking (KB 3194365)&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d actually done a little bit of searching when I first got this question by email, and I didn&amp;rsquo;t find this bug at all. But my keywords weren&amp;rsquo;t perfect.&lt;/p&gt;
&lt;p&gt;And if you&amp;rsquo;ve &lt;em&gt;ever&lt;/em&gt; searched for SQL Server bugs, you know that your keywords have to be exactly perfect, and it has to be your lucky day for you to find the bug.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.microsoft.com/en-us/help/3194365/fix-rebuilding-a-nonclustered-index-to-add-columns-by-using-create-index-with-drop-existing-on-and-online-on-causes-blocking"&gt;The bug is here&lt;/a&gt;. If you&amp;rsquo;re running SQL Server 2012, 2014, or 2016 Enterprise Edition, check your patch level if you ever run CREATE WITH DROP_EXISTING: because you probably would like to have the option for it to be at least &lt;em&gt;mostly&lt;/em&gt; online.&lt;/p&gt;
&lt;p&gt;Thanks very much to Denis for emailing about this issue! The story does have a happy ending: Denis found that the issue was resolved by patching the instance, as described in the KB.&lt;/p&gt;</description></item><item><title>New weekly newsletter: a SQL Server quiz, poll or cartoon each week</title><link>https://kendralittle.com/2017/03/27/new-weekly-newsletter-a-sql-server-quiz-poll-or-cartoon-each-week/</link><pubDate>Mon, 27 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/27/new-weekly-newsletter-a-sql-server-quiz-poll-or-cartoon-each-week/</guid><description>&lt;p&gt;I&amp;rsquo;ve started up a weekly newsletter! Sign up, and each Tuesday you&amp;rsquo;ll get a link to a quick SQL Server quiz or poll in your inbox. Most weeks there will be a cartoon thrown in there, too.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/reading-articles.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="what-youll-get"&gt;What You&amp;rsquo;ll Get&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll also give you the scoop on what&amp;rsquo;s new over at SQLWorkbooks.com. You&amp;rsquo;ll be the first to know about any free courses or new posters, and there will be goodies just for folks reading the newsletter, too.&lt;/p&gt;
&lt;p&gt;And of course I&amp;rsquo;ll holler about any breaking news in the SQL Server universe, whenever something big happens.&lt;/p&gt;
&lt;h2 id="first-issue"&gt;First Issue&lt;/h2&gt;
&lt;p&gt;My first Quizletter goes out tomorrow, March 28th! This week&amp;rsquo;s quiz is on blocking, and the link will only be in the Quizletter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: the quizletter is on hiatus for now, I&amp;rsquo;ll re-post if it&amp;rsquo;s revived with a new signup link&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>New Freebie Course: SSMS Shortcuts &amp; Secrets</title><link>https://kendralittle.com/2017/03/23/new-freebie-course-ssms-shortcuts-secrets/</link><pubDate>Thu, 23 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/23/new-freebie-course-ssms-shortcuts-secrets/</guid><description>&lt;p&gt;SQL Server Management Studio is so full of tiny buttons and options that it can be easy to miss out on secrets that could make your life easier and more fun.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got a new online course that shows you &lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;my favorite secret tricks and goodies in SSMS!&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SSMS-Shortcuts-and-Secrets-Product-Image-updated-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="this-course-is-a-little-different-each-lesson-is-a-super-quick-reference"&gt;This course is a little different: each lesson is a super-quick reference&lt;/h2&gt;
&lt;p&gt;When it comes to learning to use shortcuts in SSMS, I like to have a really quick demo, so I can immediately go practice.&lt;/p&gt;
&lt;p&gt;Each lesson in this reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Has a silent video with visual cues – no speakers or headphones are required&lt;/li&gt;
&lt;li&gt;Is one minute or less&lt;/li&gt;
&lt;li&gt;Asks your opinion in a one question, anonymous poll. Take the poll to see how everyone else voted!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="shortcuts-and-secrets-in-the-reference"&gt;Shortcuts and secrets in the reference&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Open Sessions and Execute Queries&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keyboard Shortcuts: New Session, Use Database, Autocomplete TSQL, Execute Query, Show/Hide Results&lt;/li&gt;
&lt;li&gt;Set Keyboard Shortcuts for Favorite Stored Procedures&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/select-from-cat-nip-intellisense1.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Write and Edit TSQL&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Script Table and Column Names by Dragging from Object Explorer&lt;/li&gt;
&lt;li&gt;Use the Splitter Bar when Editing Large Scripts&lt;/li&gt;
&lt;li&gt;Keyboard Shortcuts: Indent &amp;amp; UnIndent / Comment &amp;amp; UnComment&lt;/li&gt;
&lt;li&gt;Configure Object Explorer to Script Compression and Partition Schemes for Indexes&lt;/li&gt;
&lt;li&gt;Keyboard Shortcuts: Quick Find in Session, and Replace Tabs with Spaces&lt;/li&gt;
&lt;li&gt;Formatting: Regular Expressions to Add End-Lines, Type on Multiple Lines At Once&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="this-course-will-grow-over-time"&gt;This course will grow over time&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll be adding lots more goodies to this course! I&amp;rsquo;ve already got more secrets in mind, plus I&amp;rsquo;m working on a poster.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll automatically get these after you enroll. Just mark the lessons &amp;ldquo;complete&amp;rdquo; when you finish them, and new lessons will be easy to identify when they&amp;rsquo;re added.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/course/ssms-shortcuts-secrets/"&gt;Take the free course&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>When SQL Server Does NOT Use Write Ahead Logging (Dear SQL DBA Episode 35)</title><link>https://kendralittle.com/2017/03/23/when-sql-server-does-not-use-write-ahead-logging-dear-sql-dba-episode-35/</link><pubDate>Thu, 23 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/23/when-sql-server-does-not-use-write-ahead-logging-dear-sql-dba-episode-35/</guid><description>&lt;p&gt;A few episodes ago, I talked about how learning about Write Ahead Logging was a light bulb moment for me, and helped me learn tons of concepts about backups and recovery.&lt;/p&gt;
&lt;p&gt;This week, we talk about when SQL Server turns things upside down and doesn&amp;rsquo;t use write ahead logging: and what it has to do for recovery in these special cases.&lt;/p&gt;
&lt;p&gt;Watch this week’s 24 minute video. Subscribe to my &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube channel&lt;/a&gt;, or check out the audio &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast&lt;/a&gt; to listen anywhere, anytime. Links from this episode are below the video.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/2yWBBAmghT8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="links-and-references"&gt;Links and references&lt;/h2&gt;
&lt;p&gt;Download Kalen Delaney’s In-Memory OLTP Whitepaper for 2016: &lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2016/07/12/sql-server-2016-rtm-in-memory-oltp-whitepaper.aspx"&gt;http://sqlblog.com/blogs/kalen_delaney/archive/2016/07/12/sql-server-2016-rtm-in-memory-oltp-whitepaper.aspx&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The 2016 version of Kalen&amp;rsquo;s In-Memory book with Redgate is coming soon!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Erin Stellato did a demo of performance testing if In-Memory benefits a given table in the SQLSkills Insider Newsletter #149&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Join the Insider newsletter to get future demos: &lt;a href="https://www.sqlskills.com/join-the-sqlskills-insider-community/"&gt;https&lt;/a&gt;&lt;a href="https://www.sqlskills.com/join-the-sqlskills-insider-community/"&gt;://www.sqlskills.com/join-the-sqlskills-insider-community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Download Erin&amp;rsquo;s &lt;a href="http://sqlskills.us2.list-manage.com/track/click?u=729526cc5ec7737666e0a1893&amp;amp;id=9bd7ab29ab&amp;amp;e=d3a7cfb5fa"&gt;video from SQLSkills here (wvm)&lt;/a&gt; or in &lt;a href="http://sqlskills.us2.list-manage.com/track/click?u=729526cc5ec7737666e0a1893&amp;amp;id=d1b03e2b0f&amp;amp;e=d3a7cfb5fa"&gt;mov format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Download Erin&amp;rsquo;s &lt;a href="http://sqlskills.us2.list-manage1.com/track/click?u=729526cc5ec7737666e0a1893&amp;amp;id=ff4aba0f0b&amp;amp;e=d3a7cfb5fa"&gt;code samples from SQLSkills here (zip)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Columnstore Index Returns Zero Rows... Which is One Row</title><link>https://kendralittle.com/2017/03/21/columnstore-index-returns-zero-rows-which-is-one-row/</link><pubDate>Tue, 21 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/21/columnstore-index-returns-zero-rows-which-is-one-row/</guid><description>&lt;p&gt;I&amp;rsquo;ve never claimed to be great at math, but until recently I thought I knew how to count to one. Zero&amp;hellip; one. That&amp;rsquo;s what we learned in kindergarten.&lt;/p&gt;
&lt;p&gt;Apparently SQL Server didn&amp;rsquo;t go to kindergarten.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Counting-Dinosaur-e1488406844732.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Because it can&amp;rsquo;t even count to one in some execution plans.&lt;/p&gt;
&lt;p&gt;I have a very simple query. It&amp;rsquo;s running against a table with a nonclustered columnstore index.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The query returns one row, as expected. Here&amp;rsquo;s my count:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/One-Row-Count.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;For the record, that is the correct number of rows in the table. Here&amp;rsquo;s where things get weird. In the actual execution plan, the columnstore index returns zero rows.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/actual-plan-zero-rows.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Yes, this is &lt;em&gt;really&lt;/em&gt; the actual execution plan. I&amp;rsquo;m not tricking you, I promise.&lt;/p&gt;
&lt;h2 id="zero-rows-go-into-the-hash-match-but-one-row-comes-out"&gt;Zero rows go into the hash match, but one row comes out&lt;/h2&gt;
&lt;p&gt;It would appear that this hash match has conjured a row from nowhere. If we look to the left of the hash match, a row appears!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/actual-plan-one-row.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Our hash match operator is psychic. Did it phone a hotline to find out the count of this table? If so, why is the columnstore index scan in the plan in the first place?&lt;/p&gt;
&lt;h2 id="lets-look-at-the-properties-of-the-columnstore-scan"&gt;Let&amp;rsquo;s look at the properties of the columnstore scan&lt;/h2&gt;
&lt;p&gt;Things get even weirder.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/columnstore-index-scan-e1489599220984.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The columnstore index scan executed in batch mode and used 4 cores. It did a scan with each thread, although somehow it did ZERO reads and accessed ZERO partitions in my partitioned table. (Whaaatttt?)&lt;/p&gt;
&lt;p&gt;But it did do work. It did &lt;em&gt;fancy, expensive work&lt;/em&gt;. Look at those locally aggregated rows!&lt;/p&gt;
&lt;h2 id="this-is-an-enterprise-edition-optimization-for-batch-mode-columnstore"&gt;This is an Enterprise Edition optimization for batch mode columnstore&lt;/h2&gt;
&lt;p&gt;These locally aggregated rows are called &amp;lsquo;aggregate pushdown&amp;rsquo;. Aggregate pushdown is one of the enhancements that remains an Enterprise Only feature, even after SQL Server 2016 SP1. (&lt;a href="https://blogs.msdn.microsoft.com/sql_server_team/columnstore-index-standard-and-express-editions-with-sql-server-2016-sp1/"&gt;Sunil Agarwal discusses these features here&lt;/a&gt;.) It makes your columnstore indexes even faster.&lt;/p&gt;
&lt;h2 id="but-that-just-looks-wrong-it-still-outputs-a-row"&gt;But that just looks wrong! It still outputs a row!&lt;/h2&gt;
&lt;p&gt;I agree, it looks wrong. So I asked &lt;a href="http://www.nikoport.com/neugebauer/"&gt;Niko&lt;/a&gt; about it, because if anyone thinks like a columnstore index, it&amp;rsquo;s Niko. I asked when I was at SQLSaturday Portugal, too, which was just an awesome event, so I could ask in person and see his face.&lt;/p&gt;
&lt;p&gt;I asked, &amp;ldquo;Is this a bug in my execution plan? Or a feature?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Niko explained that it&amp;rsquo;s a feature. Or at least, it&amp;rsquo;s on purpose. It&amp;rsquo;s just not very good at drawing lines. What the execution plan is &lt;em&gt;trying&lt;/em&gt; to say is more like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/1-row.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The plan is trying to explain that the hash match doesn&amp;rsquo;t have to do any of the counting, because the columnstore index did it all with &lt;em&gt;enterprise magic.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="but-but-that-doesnt-look-right"&gt;But&amp;hellip; but&amp;hellip; that doesn&amp;rsquo;t look right&lt;/h2&gt;
&lt;p&gt;SQL Server is drunk. At least, that&amp;rsquo;s what I said to Niko. And his face said that he perhaps agrees with me. It&amp;rsquo;s not like Niko drew the lines, so don&amp;rsquo;t blame him! But he did confirm that this is not a bug in execution plans, this was done on purpose.&lt;/p&gt;
&lt;p&gt;I guess if it&amp;rsquo;s using &amp;ldquo;new math&amp;rdquo;, SQL Server can count those rows however it wants.&lt;/p&gt;</description></item><item><title>Time for an Interview: What accomplishment are YOU most proud of?</title><link>https://kendralittle.com/2017/03/20/time-for-an-interview-what-accomplishment-are-you-most-proud-of/</link><pubDate>Mon, 20 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/20/time-for-an-interview-what-accomplishment-are-you-most-proud-of/</guid><description>&lt;p&gt;Last week I answered a set of fun interview questions from Mohammad Darab. One question that he asked really jumped out at me:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;What are you most proud of doing/accomplishing&lt;/strong&gt;&lt;/em&gt; for the SQL Server community so far in your career?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/reflection.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="why-this-question-matters"&gt;Why This Question Matters&lt;/h2&gt;
&lt;p&gt;I looked at this question and realized that it has been a while since I&amp;rsquo;ve asked myself, &amp;ldquo;What are you proud of?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Whether it&amp;rsquo;s in the context of community contributions, or in the context of your general professional career, it&amp;rsquo;s really worth stopping and taking the time to ask yourself this question. Because I think if we are proud of ourselves for doing good things or difficult things, stopping to think about that helps us do more good things, and more difficult things.&lt;/p&gt;
&lt;h2 id="questions-to-ask-yourself"&gt;Questions to Ask Yourself&lt;/h2&gt;
&lt;p&gt;Many of us won&amp;rsquo;t come up with everything we should be proud of at first. Some of us tend to minimize our own achievements, and if you do this, you&amp;rsquo;re &lt;em&gt;particularly&lt;/em&gt; the person who could be most helped by this thought exercise. So take the time to ask yourself a few variations on the question:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What have you done that solved a problem for other people at work or in the community?&lt;/li&gt;
&lt;li&gt;What have you done that has taught other people something?&lt;/li&gt;
&lt;li&gt;What have you done that reinforced something good that someone else did?&lt;/li&gt;
&lt;li&gt;What have you done that was difficult where you had to overcome some obstacle? The obstacle could be personal, financial, social, anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These don&amp;rsquo;t all have to be difficult things. Sometimes, the things we end up being most proud of weren&amp;rsquo;t a lot of work &amp;ndash; we just had a really good idea, or were in the right place at the right time. And these don&amp;rsquo;t all have to be things that you did alone, either. Some of my proudest memories over my life are from when I did things as part of a team.&lt;/p&gt;
&lt;h2 id="my-answer"&gt;My Answer&lt;/h2&gt;
&lt;p&gt;You can read about &lt;a href="https://mohammaddarab.com/interview-kendra-little/"&gt;what I&amp;rsquo;m currently proud of in my interview here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="share-your-story"&gt;Share Your Story&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re inspired by this question, don&amp;rsquo;t wait to be interviewed. Write out what you&amp;rsquo;re proud of, either in the comments here or in a blog post of your own. I&amp;rsquo;d love to read about it.&lt;/p&gt;</description></item><item><title>Using a Tail Log Backup in a SQL Server Migration (Dear SQL DBA Episode 34)</title><link>https://kendralittle.com/2017/03/16/using-a-tail-log-backup-in-a-sql-server-migration-dear-sql-dba-episode-34/</link><pubDate>Thu, 16 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/16/using-a-tail-log-backup-in-a-sql-server-migration-dear-sql-dba-episode-34/</guid><description>&lt;p&gt;When you migrate a database, it can be useful to prove that you moved all the data and didn&amp;rsquo;t miss any transactions. Learn how to use a tail log backup in a migration scenario.&lt;/p&gt;
&lt;p&gt;Watch this week’s 13 minute video. Subscribe to my &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube channel&lt;/a&gt;, or check out the audio &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast&lt;/a&gt; to listen anywhere, anytime.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/PHNx62hMyhs?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="when-you-restore-a-full-backup-does-it-restore-to-when-you-started-the-backup-job-or-when-it-completed"&gt;When you restore a full backup, does it restore to when you started the backup job&amp;mdash; or when it completed?&lt;/h2&gt;
&lt;p&gt;In this episode, I give you the super-short answer. (Spoiler: a point near the end of when the backup was running.) For the full answer, complete with a detailed timeline to help you understand the nitty gritty, read “&lt;a href="https://technet.microsoft.com/en-us/library/2009.07.sqlbackup.aspx"&gt;Understanding SQL Server Backups&lt;/a&gt;” by Paul Randal&lt;/p&gt;
&lt;h2 id="tail-log-backups"&gt;Tail log backups&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the Book&amp;rsquo;s Online entry for &lt;a href="https://msdn.microsoft.com/en-us/library/ms179314.aspx"&gt;Tail Log backups.&lt;/a&gt; It mostly talks about using this in times of trouble (damaged databases), it also confirms&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NORECOVERY takes the database into the restoring state. This guarantees that the database does not change after the tail-log backup.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&amp;rsquo;s the really useful bit if you want your migration steps to clearly ensure that no changes can be committed after you grab this last log backup.&lt;/p&gt;</description></item><item><title>Data Type Mismatches Do Not Always Cause a Bad Implicit Conversion and Index Scan</title><link>https://kendralittle.com/2017/03/15/data-type-mismatches-dont-always-cause-a-bad-implicit-conversion-and-index-scan/</link><pubDate>Wed, 15 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/15/data-type-mismatches-dont-always-cause-a-bad-implicit-conversion-and-index-scan/</guid><description>&lt;p&gt;Here&amp;rsquo;s a great recent question that I got about query tuning and index use:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Assuming that the documented &lt;a href="https://msdn.microsoft.com/en-us/library/ms190309.aspx"&gt;levels of data type precedence in SQL Server&lt;/a&gt; are true as of SQL 2016, why does a bigint value not force an index scan when compared against an int column?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/join.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;This query is an example using the large &lt;a href="https://github.com/LitKnd/BabbyNames/releases"&gt;BabbyNames database&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50576&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this query, sure enough, we get a nice, efficient index seek:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/actual-plan-seek-bigint-to-int.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;It seeks straight to the 440 rows that it finds for this. Looking at the properties of the seek operator, it read exactly 440 rows&amp;ndash; no muss, no fuss, no waste.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/440rowsread.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="bigintshave-a-higher-precedence-than-ints"&gt;BIGINTs have a higher precedence than INTs&amp;hellip;&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s true! According to Books Online, BIGINTs have a precedence of 15 and INTs have a precedence of 16.  And right at the top of &lt;a href="https://msdn.microsoft.com/en-us/library/ms190309.aspx"&gt;the page&lt;/a&gt; it says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When an operator combines two expressions of different data types, the rules for data type precedence specify that the data type with the lower precedence is converted to the data type with the higher precedence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That would make this seem like one of those cases where every row in the table will need to be converted to a BIGINT in order to do the comparison. That would require reading every row in the index.&lt;/p&gt;
&lt;p&gt;And there&amp;rsquo;s a lot more than 440 rows.&lt;/p&gt;
&lt;h2 id="heres-what-it-looks-like-when-a-type-conversion-causes-a-scan"&gt;Here&amp;rsquo;s what it looks like when a type conversion causes a scan&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say our query was a little different&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_FirstNameByBirthDate_1966_2015_StateCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1966_2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StateCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OR&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, we have a nonclustered index on StateCode.&lt;/p&gt;
&lt;p&gt;Our query is counting rows for the state of Oregon. But we&amp;rsquo;ve cast &amp;lsquo;OR&amp;rsquo; as an NCHAR type &amp;ndash; the &amp;lsquo;N&amp;rsquo; at the beginning means this type &lt;a href="https://technet.microsoft.com/en-us/library/ms191200.aspx"&gt;supports unicode, and requires two bytes for each column&lt;/a&gt;. Unicode types support a wider range of characters than non-unicode types.&lt;/p&gt;
&lt;p&gt;But the StateCode column is CHAR(2).&lt;/p&gt;
&lt;p&gt;NCHAR has a precedence of 26, and CHAR has a precedence of 28. We are comparing a higher-precedence value (which holds more information) to a lower precedence column.&lt;/p&gt;
&lt;p&gt;Looking at the plan, this type we DO get an index scan!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/index-scan.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;This time the number of rows read is 159,405,121: all the rows in the index.&lt;/p&gt;
&lt;p&gt;If we look at the properties of that warning sign, SQL Server says that it must do an implicit conversion on the table column StateCode to compare it to the value we passed in.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/view_undeclared_data_type_results_query_plan_warning_implicit_conversion.png"&gt;
&lt;/figure&gt;
&lt;h2 id="this-isnt-new-sql-servers-been-doing-this-for-a-while"&gt;This isn&amp;rsquo;t new. SQL Server&amp;rsquo;s been doing this for a while!&lt;/h2&gt;
&lt;p&gt;When I read this question, I remembered an awesome blog post by Jonathan Kehayias. Back in 2013, he tested out a bunch of different type conversions. He mapped out which comparisons cause a seek, and which cause a scan. He even tested under more than one collation!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.sqlskills.com/blogs/jonathan/implicit-conversions-that-cause-index-scans/"&gt;Read Jonathan&amp;rsquo;s post, &amp;lsquo;Implicit Conversions that Cause Index Scans&amp;rsquo; to see the cool charts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the top chart, you see what we saw in our (much simpler) test:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comparing BIGINT to INT allows a seek&lt;/li&gt;
&lt;li&gt;Comparing NCHAR to CHAR causes a scan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Technically the top chart uses the SQL_Latin_General_CP1_CI_AS collation, and I&amp;rsquo;m using the case-sensitive version of that, but they behave the same in these cases.&lt;/p&gt;
&lt;h2 id="so-why-the-difference"&gt;So, why the difference?&lt;/h2&gt;
&lt;p&gt;Another great blog post by Paul White gives some clues as to why this might be. In, &amp;ldquo;&lt;a href="http://sqlblog.com/blogs/paul_white/archive/2011/07/19/join-performance-implicit-conversions-and-residuals.aspx"&gt;Join Performance, Implicit Conversions, and Residuals&lt;/a&gt;,&amp;rdquo; he writes about something slightly different: joining two columns of different types. But along the way Paul mentions that there are &amp;lsquo;families&amp;rsquo; of data types.&lt;/p&gt;
&lt;p&gt;INT and BIGINT are in the &lt;em&gt;same&lt;/em&gt; type family. This is the comparison that worked fine and allowed a seek on the value.&lt;/p&gt;
&lt;p&gt;CHAR and NCHAR are &lt;em&gt;not&lt;/em&gt; in the same type family. This is the comparison that forced an index scan.&lt;/p&gt;
&lt;h2 id="tldr-sometimes-we-get-lucky-but-still-be-very-careful-about-type-comparisons"&gt;TLDR: Sometimes we get lucky, but still be very careful about type comparisons&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t know of a place where this is discussed in Microsoft documentation, but Jonathan and Paul&amp;rsquo;s posts both show that it&amp;rsquo;s not as simple as the precedence of individual types.&lt;/p&gt;
&lt;p&gt;Sometimes we get lucky comparing a literal value to a column of a different type.&lt;/p&gt;
&lt;p&gt;But this is very complicated, and joining on two columns of different types in the same family without explicitly converting the type of one of the columns resulted in &lt;em&gt;worse&lt;/em&gt; performance in Paul White&amp;rsquo;s tests, when the columns allowed NULLs! (Note: I haven&amp;rsquo;t rerun those tests on 2016, but I think the general advice below still applies.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;General advice&lt;/strong&gt;: don&amp;rsquo;t rely on being lucky. Pay attention to your data types, and compare values of the same data type wherever possible.&lt;/p&gt;
&lt;p&gt;I show another example of data type comparisons gone wrong in the course, &lt;a href="https://kendralittle.com/course/tuning-problem-queries-in-table-partitioning/"&gt;Tuning Problem Queries in Table Partitioning&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Why Indexes Reduce Locks for Update and Delete Queries</title><link>https://kendralittle.com/2017/03/14/why-indexes-reduce-locks-for-update-and-delete-queries/</link><pubDate>Tue, 14 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/14/why-indexes-reduce-locks-for-update-and-delete-queries/</guid><description>&lt;p&gt;Indexes help queries run faster in SQL Server for several reasons. One of those reasons is that indexes can help your update and delete statements lock fewer rows. And I&amp;rsquo;m not only talking about shared locks, either.&lt;/p&gt;
&lt;h2 id="good-indexing-can-reducethe-number-of-modification-locks-your-update-and-delete-queries-acquire"&gt;Good indexing can reduce the number of modification locks your update and delete queries acquire&lt;/h2&gt;
&lt;p&gt;You can see this if you create a trace and look at locks_acquired for the following two queries against a test instance. Set a filter for the session_id you&amp;rsquo;re using to run the query, and add sql_text so you can see which query required which locks.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This will do an index seek on the nonclustered index [FK_Sales_Orders_CustomerID] */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hiya&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This will do an index scan on the forced index */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InternalComments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hiya&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;PK_Sales_Orders&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first query can go straight to the data that it&amp;rsquo;s going to update using an existing nonclustered index on CustomerID.&lt;/p&gt;
&lt;p&gt;The second query uses an index hint to force SQL Server to use the clustered index of the table. This simulates what would happen if we didn&amp;rsquo;t have a viable nonclustered index to find the rows quickly.&lt;/p&gt;
&lt;h2 id="how-many-locks-do-they-take-out"&gt;How many locks do they take out?&lt;/h2&gt;
&lt;p&gt;Well, they take out &lt;em&gt;a lot of locks&lt;/em&gt;. Locks are very granular, and if you do trace this you&amp;rsquo;ll find you get a lot of rows. After I traced this, I grouped the results by the mode column (lock mode), and the sql_text of the query to quickly see how many locks of which type each query took out.&lt;/p&gt;
&lt;p&gt;By &amp;ldquo;grouped&amp;rdquo;, I mean I opened the XEvents trace results in SSMS and used the Grouping function in the GUI. It was fast and easy with this amount of rows, but if it was a larger table SSMS would probably have fallen over crying.&lt;/p&gt;
&lt;p&gt;Both queries updated the same amount of rows (165). That would sure be weird if they didn&amp;rsquo;t!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The query that did the NC index seek took out &lt;strong&gt;330 update key locks&lt;/strong&gt; and 165 exclusive key locks.&lt;/li&gt;
&lt;li&gt;The query that did the clustered index scan took out &lt;strong&gt;104,184 update key locks&lt;/strong&gt; and 165 exclusive key locks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They also take out lots of other types of locks, but it&amp;rsquo;s the update locks I want to talk about here.&lt;/p&gt;
&lt;h2 id="whoa-more-than-104k-update-key-locks"&gt;Whoa, more than 104K update key locks?&lt;/h2&gt;
&lt;p&gt;Yep. It is not a coincidence that there are 104,184 rows in this table. (If you see it take out more update key locks than rows in the table, some are probably from metadata objects. The simple grouping on just mode and sql_text isn&amp;rsquo;t perfect.)&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t quite as terrible as it might sound because update locks are compatible with shared locks. However, update locks are NOT compatible with other update locks, or intent exclusive locks, or exclusive locks. (When in doubt about things like this, I like to check the official &lt;a href="https://technet.microsoft.com/en-us/library/ms186396.aspx"&gt;Lock Compatibility Matrix&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;This is one of the reasons that an OLTP database may work well in the early days, when it&amp;rsquo;s small and has a few users, but blocking can really shoot up when the data grows and our user counts grow.&lt;/p&gt;
&lt;h2 id="update-locks-matterfor-deletes-too"&gt;Update locks matter for deletes, too&lt;/h2&gt;
&lt;p&gt;Oddly enough, an update lock isn&amp;rsquo;t just for updates. The name is weird.&lt;/p&gt;
&lt;p&gt;If you run deletes and a trace for CustomerID=2 you will see something similar with lots of update locks, because deletes also use update locks.&lt;/p&gt;
&lt;p&gt;Update locks are a mechanism that SQL Server uses in the background to keep your database from exploding with deadlocks when you have multiple sessions modifying the same table at once. Sometimes blocking is better than having your queries getting killed off!&lt;/p&gt;
&lt;h2 id="more-reading"&gt;More reading&lt;/h2&gt;
&lt;p&gt;Kalen Delaney wrote more details about how update locks help avoid deadlocks, and shows &lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2009/11/13/update-locks.aspx"&gt;an example of measuring them using the sys.dm_tran_locks DMV here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="thanks-to-mike-who-askedwhat-was-up-with-this"&gt;Thanks to Mike, who asked what was up with this&lt;/h2&gt;
&lt;p&gt;Mike was curious about the answers to one of the quiz questions in &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;Troubleshooting Blocking and Deadlocks for Beginners&lt;/a&gt;, and wrote in with a great question.&lt;/p&gt;
&lt;p&gt;I think this behavior is far from obvious, and I don&amp;rsquo;t have sample code or details in the course explaining this, so I&amp;rsquo;m going to link to this post from the course to help make this more clear for others.&lt;/p&gt;
&lt;p&gt;Thanks, Mike!&lt;/p&gt;</description></item><item><title>Stack Dumps in SQL Server (Dear SQL DBA Episode 33)</title><link>https://kendralittle.com/2017/03/09/stack-dumps-in-sql-server-dear-sql-dba-episode-33/</link><pubDate>Thu, 09 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/09/stack-dumps-in-sql-server-dear-sql-dba-episode-33/</guid><description>&lt;p&gt;Learn what a Stack Dump is in SQL Server and watch a demo where I cause a stack dump against a test SQL Server instance under load. Learn how to find information about stack dumps on your SQL Server, and how to escalate them when required.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I joke around for a while at the beginning of the video. The technical bit starts at 7:15.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/zSegMTEbKuc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="read-kalen-delaneyswhitepaper-on-hekaton"&gt;Read Kalen Delaney&amp;rsquo;s whitepaper on Hekaton&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not trying to say that using In-Memory OLTP is going to cause stack dumps&amp;hellip; although now that I think about it, it doesn&amp;rsquo;t hurt to be prepared! At the beginning of this episode I mention that I&amp;rsquo;m excited to get to attend Kalen Delaney&amp;rsquo;s pre-conference session in Lisbon on Hekaton. If you&amp;rsquo;re jealous, you&amp;rsquo;d probably enjoy reading her whitepaper on &lt;a href="http://download.microsoft.com/download/8/3/6/8360731A-A27C-4684-BC88-FC7B5849A133/SQL_Server_2016_In_Memory_OLTP_White_Paper.pdf"&gt;In-Memory OLTP in SQL Server 2016 (pdf download)&lt;/a&gt;. You can also get a &lt;a href="https://www.red-gate.com/library/sql-server-internals-in-memory-oltp"&gt;free PDF of Kalen&amp;rsquo;s book on In-Memory OLTP (SQL Server 2014) from Redgate&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="meet-my-example-stack-dump"&gt;Meet my example stack dump&lt;/h2&gt;
&lt;p&gt;In the video, I show an example of a stack dump caused by running DBCC PAGE with format style 3 against a table with a filtered index in SQL Server 2014.&lt;/p&gt;
&lt;p&gt;It looks like &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/776144/dbcc-page-incorrect-output-with-filtered-indexes"&gt;this bug is fixed in SQL Server 2016, at least by SP1&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sample code to reproduce this against the AdventureWorks2012 database (which I had restored to SQL Server 2014) &lt;a href="https://gist.github.com/LitKnd/c1b70054cf5cecb587adc7d84cb128bf/edit"&gt;is in my gist here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="microsoft-support-links"&gt;Microsoft support links&lt;/h2&gt;
&lt;p&gt;In the episode this week I show a screenshot of Microsoft business support options and prices. &lt;a href="https://support.microsoft.com/en-us/gp/support-options-for-business"&gt;Here&amp;rsquo;s the link to the page where I grabbed that&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Overindexing: Missing Index DMVs and the Database Tuning Advisor</title><link>https://kendralittle.com/2017/03/08/overindexing-missing-index-dmvs-and-the-database-tuning-advisor/</link><pubDate>Wed, 08 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/08/overindexing-missing-index-dmvs-and-the-database-tuning-advisor/</guid><description>&lt;p&gt;SQL Server has tools that suggest indexes&amp;ndash; and they&amp;rsquo;ll even auto-create the indexes for you.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a huge fan of these tools because they&amp;rsquo;ve got some notable flaws: they lead to creating more indexes than you need, and they aren&amp;rsquo;t super smart about the indexes they recommend.&lt;/p&gt;
&lt;h2 id="two-queries-that-could-use-some-index-help"&gt;Two queries that could use some index help&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m using the free &lt;a href="https://github.com/LitKnd/BabbyNames/releases"&gt;BabbyNames sample database&lt;/a&gt; (small version). All the code in this example is also available &lt;a href="https://gist.github.com/LitKnd/57c3755d4535ddf069cbe896ad91769b"&gt;in a gist for easy access&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I run two queries, which each scan the clustered index of agg.FirstNameByYear:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BabbyNames&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;F&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Calliope&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="these-two-queries-generate-missing-index-requests"&gt;These two queries generate &amp;lsquo;Missing index requests&amp;rsquo;&lt;/h2&gt;
&lt;p&gt;SQL Server notices the clustered index scans when it optimizes these queries, and it quickly figures out that a nonclustered index would make these queries more efficient. It generates missing index requests.&lt;/p&gt;
&lt;p&gt;You can see missing index requests in the execution plans as green hints (&lt;a href="https://kendralittle.com/2017/03/how-to-quickly-tell-if-an-execution-plan-has-multiple-missing-index-requests/"&gt;as seen in yesterday&amp;rsquo;s post&lt;/a&gt;). You can also query them from SQL Server&amp;rsquo;s Dynamic Management Views with a query like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equality_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inequality_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;included_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_total_user_cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_est_plan_cost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_user_impact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_est_cost_reduction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_scans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_seeks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;times_requested&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_missing_index_groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_missing_index_group_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_group_handle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_handle&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_missing_index_details&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_handle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_handle&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;* This simple query doesn&amp;rsquo;t sort or prioritize the requests, it just returns the raw info&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the missing index requests for agg.FirstNameByYear look like in this case:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/missing-indexes-babbynames.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The missing index feature has a few limitations. The limitations &lt;a href="https://technet.microsoft.com/en-us/library/ms345485.aspx"&gt;are documented&lt;/a&gt;, but the problem is that most people don&amp;rsquo;t know about the documentation. The feature doesn&amp;rsquo;t suggest key column order or fine tune your indexes.&lt;/p&gt;
&lt;p&gt;But I think the biggest limitation is that the missing index feature doesn&amp;rsquo;t provide a way to learn about the queries making the request &amp;ndash; and that link would be extremely helpful so that &lt;em&gt;you&lt;/em&gt; can fine tune your indexes!&lt;/p&gt;
&lt;p&gt;There are a couple of problems with the requests for these relatively simple queries:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The second line shows that the index with KEY (Gender) and INCLUDE (FirstNameId, NameCount) has been requested 30 times. The first sample query, which runs 10 times, is asking for &lt;em&gt;both&lt;/em&gt; of these indexes. There is no way to know from just looking at this list that the query would do very well with just one index on KEY (FirstNameId, Gender) INCLUDE (NameCount).&lt;/li&gt;
&lt;li&gt;The recommendation for an index with KEY(Gender) and INCLUDE (FirstNameId, NameCount) isn&amp;rsquo;t great for the TOP 100 query that executed 20 times, either. That query has an equality predicate on Gender, and wants the TOP 100 rows ordered by NameCount DESC: it would do very well with an index on KEY (Gender, NameCount DESC) INCLUDE (FirstNameId). With the suggested index, it will have to scan all the rows for every male baby &amp;ndash; about half the index&amp;ndash; then sort them all in memory by NameCount. Bummer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We have confusing advice. If we don&amp;rsquo;t know better, we&amp;rsquo;ll end up over-indexing &amp;ndash; and still not creating the best index for one of the queries.&lt;/p&gt;
&lt;h2 id="does-the-database-tuning-advisor-do-better"&gt;Does the Database Tuning Advisor do better?&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t love running the DTA directly against SQL Servers that you care about: if it fails during its run, it leaves a bunch of temporary objects behind. I know that this happens a lot, because I&amp;rsquo;ve found those temporary objects in SQL Servers scattered around the world. It&amp;rsquo;s like space trash: it doesn&amp;rsquo;t pose an immediate threat, but it&amp;rsquo;s sloppy.&lt;/p&gt;
&lt;p&gt;But, for science, I ran the DTA against this database, using the execution plan cache after I ran these queries.&lt;/p&gt;
&lt;p&gt;The DTA suggested that I create four indexes:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dta-recommendation.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;We&amp;rsquo;ve got problems here too, it just looks fancier.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For the TOP 100/ ORDER BY query which ran 20 times, this recommended KEY (NameCount DESC, Gender) INCLUDE (FirstNameId). We have an equality predicate in that query on Gender. With this recommended index, SQL Server will look at rows for both genders with the highest names until it finds the 100 rows for boy babies with the most frequent names (it&amp;rsquo;ll look about approximately twice the amount of rows it would need to). It&amp;rsquo;s not horrible, because the TOP operator is smart enough to stop after it &amp;lsquo;finds&amp;rsquo; 100 rows, but it&amp;rsquo;s not brilliant.&lt;/li&gt;
&lt;li&gt;One index request on ref.FirstName is baffling to me. The ref.FirstName table has a clustered primary key on FirstNameId. We can already easily seek to any row based on FirstNameId, and access the FirstName column very efficiently. Yet a duplicate index is being recommended here.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="whats-wrong-with-over-indexing"&gt;What&amp;rsquo;s wrong with over-indexing?&lt;/h2&gt;
&lt;p&gt;Overindexing isn&amp;rsquo;t great: it wastes storage, wastes memory, prolongs index maintenance and corruption checking, and makes restores take longer.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t harmless. It&amp;rsquo;s like throwing junk in your closet. At first it&amp;rsquo;s no big deal. Eventually, you can barely open the door without things falling on your head.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/pablo-unsplash-missing-index-requests-e1488818395910-300x150.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="what-would-i-really-do-in-this-case"&gt;What would I really do in this case?&lt;/h2&gt;
&lt;p&gt;The query that runs 10 times would do very well with either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KEY (Gender, FirstNameId) INCLUDE (NameCount)&lt;/li&gt;
&lt;li&gt;KEY (FirstNameId, Gender) INCLUDE (NameCount)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The query that runs 20 times would do very well with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KEY (Gender, NameCount DESC) INCLUDE FirstNameId&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have a small conundrum here, because key order really matters.  There&amp;rsquo;s no &amp;ldquo;perfect&amp;rdquo; way to combine these indexes, because only one column can be second in the list of keys. And &amp;lsquo;Gender&amp;rsquo; is not very selective as a leading key column.&lt;/p&gt;
&lt;p&gt;I see this as a prioritization problem. &lt;em&gt;&lt;strong&gt;What are the performance requirements for each query?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once we know that, the next problem is, &lt;em&gt;&lt;strong&gt;how long are the queries actually taking?&lt;/strong&gt;&lt;/em&gt; It&amp;rsquo;s possible that I don&amp;rsquo;t need to do anything and that the performance of my queries is totally acceptable.&lt;/p&gt;
&lt;p&gt;Remember: just because you see an index request, that doesn&amp;rsquo;t prove you have slow queries! All it means is that the optimizer guessed something could be faster when it was guessing about how to run a query, before the query even executed.&lt;/p&gt;
&lt;p&gt;If the &amp;ldquo;TOP 100&amp;rdquo; query is more important and I create only the following index, it&amp;rsquo;s great for the &amp;lsquo;TOP 100&amp;quot; query. It&amp;rsquo;s good enough for the other query to result in CPU time of 45 milliseconds and elapsed time of 18 milliseconds.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_iamapersonnotamachine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByYear&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;* Sorry about the terrible index name&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;* &lt;em&gt;I didn&amp;rsquo;t specify NameCount as DESC. It doesn&amp;rsquo;t make a difference in this case: SQL Server can do a backward scan. Although that zone of the plan will be serial, it&amp;rsquo;s feeding into a &lt;a href="http://sqlblog.com/blogs/paul_white/archive/2011/12/23/forcing-a-parallel-query-execution-plan.aspx"&gt;TOP operator anyway, which requires a serial zone&lt;/a&gt;. And it&amp;rsquo;s able to stop after it reads 100 rows.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If we frequently use predicates on the FirstName column on ref.FirstName, it makes sense to index it, even though it&amp;rsquo;s a tiny table. So I&amp;rsquo;d do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_FirstName_FirstName_INCLUDES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="thoughts-and-takeaways"&gt;Thoughts and Takeaways&lt;/h2&gt;
&lt;p&gt;The &amp;lsquo;Missing Indexes&amp;rsquo; feature is like a two year old: it asks for what it wants in the moment. It often asks for too much, or not the right thing. That&amp;rsquo;s understandable: these index requests have to be generated super fast during query optimization. SQL Server doesn&amp;rsquo;t have time to sit around and ponder. It&amp;rsquo;s up to you to figure out &lt;em&gt;why&lt;/em&gt; it&amp;rsquo;s asking for something and whether or not it should get it &amp;ndash; and if you want to do that well, you&amp;rsquo;re going to have to track down the queries that are making the requests.&lt;/p&gt;
&lt;p&gt;That means doing some legwork and identifying the query execution plans that are the most important to index. You can do that using the execution plan cache, Query Store, or a custom monitoring tool.&lt;/p&gt;
&lt;p&gt;As for the Database Tuning Advisor, it doesn&amp;rsquo;t have the excuse of having to work super fast during query compilation. It&amp;rsquo;s still prone to over-indexing and littering in your database if it hits a hiccup. I&amp;rsquo;ve also known it to recommend some really wacky clustered indexes that people applied because they thought the DTA must follow best practices. I just can&amp;rsquo;t find a way to be a fan of the DTA.&lt;/p&gt;
&lt;h2 id="theres-a-bright-side-to-this"&gt;There&amp;rsquo;s a bright side to this&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=DODwnYzrbPI"&gt;The computers haven&amp;rsquo;t quite taken our jobs, yet&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How to Quickly Tell if an Execution Plan has Multiple Missing Index Requests</title><link>https://kendralittle.com/2017/03/07/how-to-quickly-tell-if-an-execution-plan-has-multiple-missing-index-requests/</link><pubDate>Tue, 07 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/07/how-to-quickly-tell-if-an-execution-plan-has-multiple-missing-index-requests/</guid><description>&lt;p&gt;Ever see those little green messages at the top of an execution plan?&lt;/p&gt;
&lt;p&gt;Those are missing index suggestions.&lt;/p&gt;
&lt;p&gt;SQL Server &lt;em&gt;loves&lt;/em&gt; to suggest that you consider changing up your index game.&lt;/p&gt;
&lt;p&gt;The hint looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/IndexHint.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="there-may-be-more-than-one-index-suggestion---but-there-is-never-more-than-one-green-hint"&gt;There may be more than one index suggestion - but there is never more than one green hint&lt;/h2&gt;
&lt;p&gt;SQL Server can suggest multiple indexes for a single query. It&amp;rsquo;s difficult to tell when that happens, though.&lt;/p&gt;
&lt;p&gt;Not only will you only ever see one hint at the top of the plan, it isn&amp;rsquo;t necessarily the index that SQL Server thinks will help the most! And if you right click on the plan and script the index to a new window, you &lt;em&gt;only&lt;/em&gt; get the index request from the green hint. If there&amp;rsquo;s another one, it doesn&amp;rsquo;t script.&lt;/p&gt;
&lt;p&gt;You can right click the plan and look at the XML and look for the missing indexes section. But it&amp;rsquo;s a bit of a pain to do each time. You can also open the plan in the &lt;a href="https://www.sentryone.com/plan-explorer"&gt;free Sentry One Plan Explorer&lt;/a&gt; (or run the query from Plan Explorer in the first place), but you may not always have it installed.&lt;/p&gt;
&lt;h2 id="a-quick-check-look-at-the-properties-of-the-select-operator"&gt;A quick check: look at the properties of the select operator&lt;/h2&gt;
&lt;p&gt;With that top left operator highlighted, I open the properties window and, voila&amp;ndash; I can expand &amp;lsquo;Missing indexes&amp;rsquo; and quickly tell that there are two index suggestions for this query:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/missing-index-details-properties-pane.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="the-green-hint-isnt-even-the-index-sql-server-thinks-will-help-most"&gt;The green hint isn&amp;rsquo;t even the index SQL Server thinks will help most&lt;/h2&gt;
&lt;p&gt;Check out &lt;a href="https://kendralittle.com/2017/02/22/understanding-avg_total_user_cost-and-avg_user_impact-in-missing-index-requests/"&gt;those &amp;lsquo;impact&amp;rsquo; numbers&lt;/a&gt;. SQL Server thinks one of these indexes will reduce the estimated cost of the query plan by 93.6%. Unfortunately that is &lt;em&gt;not&lt;/em&gt; the hint showing in green&amp;ndash; and it&amp;rsquo;s not the hint that will script out if I right click the plan and script indexes.&lt;/p&gt;
&lt;h2 id="whats-the-best-way-to-view-bothindex-requests"&gt;What&amp;rsquo;s the best way to view both index requests?&lt;/h2&gt;
&lt;p&gt;You can expand out all the nodes to view the index requests in the properties pane&amp;ndash; but it&amp;rsquo;s kind of a pain, no pun intended. I really like this just for a quick check of the suggestion count, and then I&amp;rsquo;ll either go to the XML or to Plan Explorer. (Much of the time there&amp;rsquo;s just one suggestion.)&lt;/p&gt;
&lt;h2 id="should-we-add-both-indexes"&gt;Should we add both indexes?&lt;/h2&gt;
&lt;p&gt;Nope. The missing index request is being a bit over-eager here, and it&amp;rsquo;s asking for more than it needs. I&amp;rsquo;ll write more about that in tomorrow&amp;rsquo;s post.&lt;/p&gt;</description></item><item><title>New Course: Tuning Problem Queries in Table Partitioning</title><link>https://kendralittle.com/2017/03/02/new-course-tuning-problem-queries-in-table-partitioning/</link><pubDate>Thu, 02 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/02/new-course-tuning-problem-queries-in-table-partitioning/</guid><description>&lt;p&gt;As of SQL Server 2016 SP1, you can now use partitioning in Standard, Web, and even Express Edition of SQL Server.&lt;/p&gt;
&lt;p&gt;Everything&amp;rsquo;s gonna be fast! Right?&lt;/p&gt;
&lt;p&gt;Well, not quite. But no worries, &lt;a href="https://kendralittle.com/course/tuning-problem-queries-in-table-partitioning/"&gt;this course is now free&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Troubleshooting-Problem-Queries-in-Table-Partitioning-Product-Image-1000.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="learn-to-identify-regressed-queries-against-partitioned-tables"&gt;Learn to identify regressed queries against partitioned tables&lt;/h2&gt;
&lt;p&gt;My new course shows you patterns that slow down when you partition your tables, and gives you options to speed up your queries using index and TSQL changes.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll also learn to use query execution plans to troubleshoot regressed queries using partitioned tables. You will learn what “non-aligned” indexes are, how to tell how many partitions a query is really using, and why the optimizer sees partitioned indexes differently.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll also see a lot of dinosaur drawings.&lt;/p&gt;
&lt;h2 id="bonus-theres-a-little-columnstore-in-there-too"&gt;Bonus: there&amp;rsquo;s a little columnstore in there, too&lt;/h2&gt;
&lt;p&gt;Partitioning can pair delightfully with columnstore indexes, so the demos in the course feature a nonclustered columnstore index as our guest star. You&amp;rsquo;ll get a peek at performance comparisons for this index between Enterprise and Standard Edition, too.&lt;/p&gt;
&lt;h2 id="dive-in"&gt;Dive in!&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/course/tuning-problem-queries-in-table-partitioning/"&gt;This course is now freely available for everyone&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>WAL: The concept that makes recovery models &amp; backups make sense (Dear SQL DBA Episode 32)</title><link>https://kendralittle.com/2017/03/02/wal-the-concept-that-makes-recovery-models-backups-make-sense-dear-sql-dba-episode-32/</link><pubDate>Thu, 02 Mar 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/03/02/wal-the-concept-that-makes-recovery-models-backups-make-sense-dear-sql-dba-episode-32/</guid><description>&lt;p&gt;When you&amp;rsquo;re a Junior DBA, it&amp;rsquo;s really hard to take in all the information out there.&lt;/p&gt;
&lt;p&gt;Learn about write ahead logging: the concept that can help you make sense of recovery models and backup strategies in SQL Server. This is a foundational concept that helps you understand how SQL Server works.&lt;/p&gt;
&lt;p&gt;In this week&amp;rsquo;s episode, I tell the story of the &amp;ldquo;Wow!&amp;rdquo; moment when I learned about write ahead logging from &lt;a href="http://www.sqlskills.com/blogs/kimberly/"&gt;Kimberly Tripp of SQLSkills.com&lt;/a&gt; way back when I was a Junior DBA. I give my own take on how write ahead logging works in SQL Server.&lt;/p&gt;
&lt;p&gt;Predictably, my version has goofy drawings.&lt;/p&gt;
&lt;p&gt;Watch this week’s 18 minute episode, and subscribe to my &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube channel&lt;/a&gt; if you&amp;rsquo;d like to see more. You can also get future episodes in the audio &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast&lt;/a&gt; if you like to listen on the go.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I do some storytelling at the beginning of this episode. The tech content starts 8 minutes in if you&amp;rsquo;d like to skip straight to that part.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/rZOU0ExRgB0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="further-reading"&gt;Further reading&lt;/h2&gt;
&lt;p&gt;Junior DBA Training Plan: &lt;a href="https://kendralittle.com/2016/03/29/training-plan-for-junior-dbas-learning-sql-server/"&gt;/2016/03/29/training-plan-for-junior-dbas-learning-sql-server/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Learn about the Write Ahead Transaction Log on TechNet: &lt;a href="https://technet.microsoft.com/en-us/library/ms186259.aspx"&gt;https://technet.microsoft.com/en-us/library/ms186259.aspx&lt;/a&gt;&lt;/p&gt;</description></item><item><title>DBCC CLONEDATABASE Does NOT Clone Index Usage Statistics</title><link>https://kendralittle.com/2017/02/28/dbcc-clonedatabase-does-not-clone-index-usage-statistics/</link><pubDate>Tue, 28 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/28/dbcc-clonedatabase-does-not-clone-index-usage-statistics/</guid><description>&lt;p&gt;The word &amp;lsquo;statistics&amp;rsquo; is awfully confusing in SQL Server&lt;/p&gt;
&lt;p&gt;It can mean &amp;ldquo;&lt;a href="https://msdn.microsoft.com/en-us/library/ms190397.aspx"&gt;statistics&lt;/a&gt;&amp;rdquo; themselves &amp;ndash; little objects that describe the distribution of data in columns or indexes to help the optimizer.&lt;/p&gt;
&lt;p&gt;Or it can mean &amp;ldquo;usage statistics&amp;rdquo; -  dynamic management views that let you see how many times an index has been used or requested, how many times a query has been run, that kind of thing.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/clones-e1487291347274.png" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="i-was-curious-when-i-read-that-dbcc-clone-database-copies-statistics-for-all-indexes"&gt;I was curious when I read that DBCC CLONE DATABASE &amp;ldquo;copies statistics for all indexes&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;When the DBCC CLONEDATABASE command was released for SQL Server 2014 SP2 and SQL Server 2016 SP1, it came with &lt;a href="https://support.microsoft.com/en-us/help/3177838/how-to-use-dbcc-clonedatabase-to-generate-a-schema-and-statistics-only-copy-of-a-user-database-in-sql-server-2014-sp2-and-sql-server-2016-sp1"&gt;detailed documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The wording is just confusing.  It seemed pretty clear that column and index statistics, the ones which describe the data, are being cloned. But I got a little hopeful that perhaps some index &lt;em&gt;usage&lt;/em&gt; statistics might be copied as well.&lt;/p&gt;
&lt;p&gt;So I did some testing &lt;a href="https://gist.github.com/LitKnd/5a5a6f68b750c7f510eea12c70700db6"&gt;with the sample code in this Gist&lt;/a&gt;, and here&amp;rsquo;s what I found.&lt;/p&gt;
&lt;h2 id="dbcc-clonedatabase-doesnt-copy-any-information-from-the-index-usage-or-missing-index-dmvs"&gt;DBCC CLONEDATABASE doesn&amp;rsquo;t copy any information from the index usage or  missing index DMVs&lt;/h2&gt;
&lt;p&gt;Your new cloned database has no idea how many times an index was used, or which indexes were requested in the database you cloned.&lt;/p&gt;
&lt;h2 id="the-index-usage-and-missing-index-dmvs-will-record-information-in-your-cloned-database"&gt;The index usage and missing index DMVs will record information in your cloned database&lt;/h2&gt;
&lt;p&gt;If anyone runs queries against the clone database for testing purposes, SQL Server will record the index usage and index requests in the missing index DMVs as normal.&lt;/p&gt;
&lt;p&gt;This works even while the cloned database is read-only.&lt;/p&gt;
&lt;h2 id="is-dbcc-clonedatabase-safe"&gt;Is DBCC CLONEDATABASE safe?&lt;/h2&gt;
&lt;p&gt;This new feature is documented and fully supported. I tend to be pretty careful using new features against critical production databases until I&amp;rsquo;m quite familiar with them, though. I&amp;rsquo;d rather get to know this in test environments for a while before declaring, &amp;ldquo;it&amp;rsquo;s all good&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Checking connect.microsoft.com&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ola Hallengren has &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/3112504/dbcc-clonedatabase-cannot-insert-duplicate-key-row-in-object-sys-plan-persist-context-settings-with-unique-index-plan-persist-context-settings-cidx"&gt;filed a bug related to clonedatabase and Query Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Joey D&amp;rsquo;Antoni &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/3118960/drop-table-fails-on-temporal-tables-in-cloned-database"&gt;ran into a bug with clonedatabase and temporal tables&lt;/a&gt;, and&lt;/li&gt;
&lt;li&gt;Ben Whitman &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/2926086/dbcc-databaseclone-fails-on-sys-sysowners"&gt;found a database he can&amp;rsquo;t clone&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those bugs haven&amp;rsquo;t been responded to yet, and I don&amp;rsquo;t mean to make DBCC CLONEDATABASE sound horrible, just be aware.&lt;/p&gt;
&lt;h2 id="summing-up"&gt;Summing  up&amp;hellip;&lt;/h2&gt;
&lt;p&gt;If you look at any information in the index usage or missing index DMVs in a &amp;ldquo;cloned&amp;rdquo; database, the information  you see just reflects activity run against the clone&amp;ndash; not against the original database.&lt;/p&gt;</description></item><item><title>The BabbyNames Sample Database - Now on GitHub</title><link>https://kendralittle.com/2017/02/28/the-babbynames-sample-database-now-on-github/</link><pubDate>Tue, 28 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/28/the-babbynames-sample-database-now-on-github/</guid><description>&lt;p&gt;1960 was the most popular year to name your baby &amp;lsquo;Dino&amp;rsquo;, with 386 Dinos born.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/BabyDino-ISQLGood-300x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I love playing around with the free data that the Social Security Administration publishes on &lt;a href="https://catalog.data.gov/dataset/baby-names-from-social-security-card-applications-national-level-data"&gt;baby names&lt;/a&gt; each year.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s fun to manipulate the dataset in a variety of ways, and you learn odd things along the way&amp;hellip; like the fact that more than 7,000 babies in the US have been named &amp;lsquo;Kale&amp;rsquo; since 1917.&lt;/p&gt;
&lt;h2 id="ive-got-more-facts-about-kale-than-you-knew-you-wanted"&gt;I&amp;rsquo;ve got more facts about Kale than you knew you wanted&lt;/h2&gt;
&lt;p&gt;The most popular year to be named Kale was 2008 (567 kales), which predates the time when the vegetable became super popular by at least a few years. More kale on your plate doesn&amp;rsquo;t mean you want to raise a &amp;lsquo;Kale&amp;rsquo;: there were only 175 Kales named in 2015.&lt;/p&gt;
&lt;h2 id="are-those-kale-babies-girls-or-are-they-boys"&gt;Are those Kale Babies girls, or are they boys?&lt;/h2&gt;
&lt;p&gt;If you want to know, you&amp;rsquo;re going to have to download the BabbyNames database yourself&amp;ndash; or grab the scripts and source data and build it.&lt;/p&gt;
&lt;h2 id="its-easy-to-download"&gt;It&amp;rsquo;s easy to download&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/LitKnd/BabbyNames/releases"&gt;It&amp;rsquo;s all free over on GitHub.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No login required, no nothin&amp;rsquo;.&lt;/p&gt;
&lt;h2 id="why-would-i-want-this"&gt;&amp;ldquo;Why would I want this?&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;Even if you don&amp;rsquo;t have a natural curiosity about babies named after vegetables, it can be fun to play around with different data sources to test queries and features. Not that I don&amp;rsquo;t love &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;Microsoft&amp;rsquo;s WideWorldImporters&lt;/a&gt;, I just sometimes want something a little different.&lt;/p&gt;
&lt;h2 id="why-is-it-named-babbynames"&gt;&amp;ldquo;Why is it named BabbyNames?&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;There are at least two lame jokes related to the name:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;rsquo;ve heard of &lt;a href="https://xkcd.com/327/"&gt;Little Bobby Tables&lt;/a&gt;? This is Little Babby Tables.&lt;/li&gt;
&lt;li&gt;An internet meme famously asked the question, &amp;ldquo;How is Babby Formed?&amp;rdquo; This database answers the question, &amp;ldquo;How is Babby Named?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But I like the name because I find the word &amp;ldquo;&lt;a href="http://www.bbc.co.uk/ulsterscots/words/babbie-babby"&gt;Babby&lt;/a&gt;&amp;rdquo; to be funny, all by itself.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;</description></item><item><title>Will the Cloud Eat My DBA Job? (Dear SQL DBA Episode 31)</title><link>https://kendralittle.com/2017/02/23/will-the-cloud-eat-my-dba-job-dear-sql-dba-episode-31/</link><pubDate>Thu, 23 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/23/will-the-cloud-eat-my-dba-job-dear-sql-dba-episode-31/</guid><description>&lt;p&gt;Will cloud services render DBAs obsolete? Does the cloud mean that developers will use less of SQL Server? In this post I talk about the future of database administration and give tips on strategizing your career.&lt;/p&gt;
&lt;p&gt;Watch this week&amp;rsquo;s 28 minute episode, or scroll down to read a written version of the answer. Us YouTubers love it when you subscribe to our &lt;a href="https://www.youtube.com/channel/UCrJ8WLrVoKxL94mKv2akxTA"&gt;YouTube channels&lt;/a&gt;. You can also get this by &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864?mt=2"&gt;podcast (and I would love it if you left a review on iTunes)&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/DODwnYzrbPI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA&amp;hellip;&lt;/p&gt;
&lt;p&gt;I moved into the role of DBA about a year ago and still have a lot to learn, however I&amp;rsquo;m worried…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud adoption may move more and more companies away from SQL Server (due to cost, for instance)&lt;/li&gt;
&lt;li&gt;As the transition to the cloud becomes more commonplace the DBA job will become a service included in that offering&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I responded with a few questions of my own:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What made you decide to be a SQL Server DBA, specifically?&lt;/li&gt;
&lt;li&gt;What do you like about being a DBA? What parts of your job do you wish you could do all the time?&lt;/li&gt;
&lt;li&gt;Are you curious about cloud technologies at all? Or do they seem uninteresting to you?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&amp;rsquo;re talking about career strategy here. It&amp;rsquo;s important to reflect a little on how you got to the point you&amp;rsquo;re at now, and what you enjoy doing and what you&amp;rsquo;re interested in in this context.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll get back to how those questions were answered soon.&lt;/p&gt;
&lt;h2 id="lots-of-things-have-been-reported-to-kill-the-dba-over-the-years"&gt;Lots of things have been reported to kill the DBA over the years&lt;/h2&gt;
&lt;p&gt;SQL Server 2005 was said to be &amp;ldquo;self-tuning&amp;rdquo;! Who needs a DBA when the instance tunes itself? (Apparently everyone.)&lt;/p&gt;
&lt;p&gt;Outsourcing: All the DBA jobs are going to X location, then Y location, then Z location. Then back to X. DBA jobs have become more global, but &amp;ldquo;outsourcing&amp;rdquo; hasn&amp;rsquo;t gotten rid of DBA jobs in the United States. It has been part of the trend to make working remotely more normal and easy, which is generally good for DBAs.&lt;/p&gt;
&lt;p&gt;DevOps! All the developers will manage everything. And somehow know to do so.  I love Dev Ops, and I have seen it wipe out some QA departments, but I haven&amp;rsquo;t seen it wipe out DBAs. I think it&amp;rsquo;s fun to be a DBA working with a Dev Ops team.&lt;/p&gt;
&lt;h2 id="one-job-is-going-away-slowly"&gt;One job is going away… slowly&lt;/h2&gt;
&lt;p&gt;“Old School &lt;a href="https://society6.com/product/databass_t-shirt#s6-3289695p15a4v75a5v18a11v49"&gt;Databass&lt;/a&gt; Administrator”&lt;/p&gt;
&lt;p&gt;Duties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installs SQL Server&lt;/li&gt;
&lt;li&gt;Sets up and monitors jobs for backups, CHECKDB, and index maintenance&lt;/li&gt;
&lt;li&gt;Manages user permissions&lt;/li&gt;
&lt;li&gt;Stays in cube, silently&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don&amp;rsquo;t think the cloud specifically is killing off this role. IT teams are being demanded to communicate better, pay more attention to their customers, be more dynamic and specialized.&lt;/p&gt;
&lt;h2 id="whos-a-dbas-1-customer"&gt;Who’s a DBA’s #1 customer?&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dba-number-1-customer-e1487785688911.png"&gt;
&lt;/figure&gt;
&lt;h2 id="developers-wanna-develop"&gt;Developers wanna develop&lt;/h2&gt;
&lt;p&gt;The cloud enables developers to use a lot of technologies.&lt;/p&gt;
&lt;p&gt;But that doesn’t necessarily mean &lt;em&gt;less&lt;/em&gt; SQL Server will be used.&lt;/p&gt;
&lt;p&gt;The cloud is also bringing new ways for SQL Server to be cost effective – like elastic pools.&lt;/p&gt;
&lt;p&gt;Developers have a massive challenge: there&amp;rsquo;s an incredible amount for them to learn.&lt;/p&gt;
&lt;h2 id="microsoft-has-been-changing"&gt;Microsoft has been changing&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not just cloud &amp;ndash; it&amp;rsquo;s things like SQL Server on Linux in vNext of SQL Server.&lt;/p&gt;
&lt;p&gt;Yeah, you can spin up a Linux VM in the cloud and run SQL Server on it. But you can also do it on prem. Or in a container. You can do it anywhere. &lt;a href="https://www.wired.com/2017/01/microsofts-old-school-database-surprise-software-hit-year/"&gt;That&amp;rsquo;s really cool&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Microsoft is also embracing lots of technology in their cloud. You can bring data from multiple data sources together&amp;ndash; including SQL Server.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t get threatened by the fact that it&amp;rsquo;s not all SQL Server. If customers can do more and build more, and if there&amp;rsquo;s many ways to include SQL Server in that, it&amp;rsquo;s going to get used. It has tons of cool features for performance, and it&amp;rsquo;s a proven relational database with a really solid foundation.&lt;/p&gt;
&lt;h2 id="developers-are-still-gonna-need-help"&gt;Developers are still gonna need help&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;“This looks weird, what’s happening in the database?”&lt;/li&gt;
&lt;li&gt;“Why is this slow?”&lt;/li&gt;
&lt;li&gt;“What can we do to make queries faster without changing the code?”&lt;/li&gt;
&lt;li&gt;“Is there a way to do this more cheaply?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And also…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Can we roll our own solution?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The complexity developers face is only expanding. For those teams who choose SQL Server, there&amp;rsquo;s plenty of need for specialists.&lt;/p&gt;
&lt;h2 id="business-owners-will-still-need-help"&gt;Business owners will still need help&lt;/h2&gt;
&lt;p&gt;They have their own questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“What are the developers not seeing?”&lt;/li&gt;
&lt;li&gt;“Are we meeting our SLAs, RPOs, RTOs and other acronyms?”&lt;/li&gt;
&lt;li&gt;“Is our data secure?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And also…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Should we be in the cloud, or running our own?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember how once upon a time, virtualization was going to completely take over everything? It definitely did become very common, but there were still plenty of companies who kept their SQL Servers using physical hardware for performance reasons. There are plenty of others who virtualized, then reverted to physical as well. And now there&amp;rsquo;s a trend toward the new hotness of containers.&lt;/p&gt;
&lt;p&gt;As the options increase, the need for a SQL Server DBA who&amp;rsquo;s aware of the pros and cons of each just goes up.&lt;/p&gt;
&lt;h2 id="dba-specializations"&gt;DBA Specializations&lt;/h2&gt;
&lt;p&gt;Sysadmin / Platform&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scripting and managing large private implementations&lt;/li&gt;
&lt;li&gt;High Availability and Disaster Recovery&lt;/li&gt;
&lt;li&gt;Storage specializations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Performance tuning / architecture&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performance tuning critical workloads&lt;/li&gt;
&lt;li&gt;Specialized code design patterns for high transaction workloads&lt;/li&gt;
&lt;li&gt;Index tuning and new technologies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloud is a part of both of these. Many companies will use the cloud for failover. Many will come to use it primarily. Even then, which cloud do you use? Which way do you deploy to best suit your cost requirements and service level agreements? How do you manage it as it evolves?&lt;/p&gt;
&lt;h2 id="operations-can-be-its-own-specialization"&gt;Operations can be its own specialization&lt;/h2&gt;
&lt;p&gt;I used to work with two men who came from the “punch-card” days. When I met them they ran operations for a set of proprietary Hadoop-like clusters for a dot com. They were doing NOSQL before I ever heard it called NOSQL.&lt;/p&gt;
&lt;p&gt;They were &lt;em&gt;really good&lt;/em&gt; at operations. They adapted to new things to manage, and they did it very well.&lt;/p&gt;
&lt;p&gt;That made me realize that as long as I&amp;rsquo;m good at solving a problem for a business with technology, I&amp;rsquo;m going to be able to find a job. I just need to keep adapting as the technology evolves.&lt;/p&gt;
&lt;h2 id="business-intelligence-is-another-example"&gt;Business intelligence is another example&lt;/h2&gt;
&lt;p&gt;The rise of self-serve data sounded like it was going to put BI folks out of business at the beginning.&lt;/p&gt;
&lt;p&gt;After all, PowerPivot used &lt;em&gt;“The Engine of the Devil!”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Who needs to build cubes anymore if people can just do everything they need in an Excel spreadsheet that references the cloud?&lt;/p&gt;
&lt;h2 id="this-customer-wants-their-bi-team-more-than-ever"&gt;This customer wants their BI team more than ever&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/this-customer-1024x512.png"&gt;
&lt;/figure&gt;
&lt;h2 id="bi-consultants-now"&gt;BI consultants now&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/BI-Consultants-1024x512.png"&gt;
&lt;/figure&gt;
&lt;p&gt;I don&amp;rsquo;t work in Business Intelligence, but people seem to be really productive, happy, and active in that field.&lt;/p&gt;
&lt;p&gt;More options on how to get things done resulted in more work, and more demand for interesting data to work with from business users. People want to figure out how to make their data meaningful in new ways.&lt;/p&gt;
&lt;h2 id="what-if-youre-just-starting-out"&gt;What if you’re just starting out?&lt;/h2&gt;
&lt;p&gt;If you are&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fresh in the industry, no experience&lt;/li&gt;
&lt;li&gt;Someone who loves working with data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Should you focus on &lt;em&gt;just&lt;/em&gt; Microsoft SQL Server?&lt;/p&gt;
&lt;p&gt;Well, no, but that has nothing to do with SQL Server, or even the cloud specifically. &lt;em&gt;Don’t settle down too fast. Why marry one technology before even getting to know others?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re in this position, it&amp;rsquo;s an amazing time to experiment with all the technologies out there. This definitely includes cloud technology, but give yourself freedom to explore and try as many new things as you can get your hands on.&lt;/p&gt;
&lt;h2 id="our-questioner-isnt-in-that-position"&gt;Our questioner isn’t in that position&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s how they answered my questions&amp;hellip;&lt;/p&gt;
&lt;p&gt;1.What made you decide to be a SQL Server DBA?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Accidental DBA, support background&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.What do you like about being a DBA?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;_Inner workings of SQL Server, flagship technologies. (_&lt;em&gt;NOT&lt;/em&gt; &lt;em&gt;writing reports.)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3.Are you curious about cloud technologies?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-cloud-is-part-of-your-job-security"&gt;The cloud is &lt;em&gt;part&lt;/em&gt; of your job security&lt;/h2&gt;
&lt;p&gt;Get to know different options to deploy SQL Server to the cloud.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strengths&lt;/li&gt;
&lt;li&gt;Weaknesses / limitations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ask questions around these areas&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;HA/DR&lt;/li&gt;
&lt;li&gt;How to support it / what maintenance is required&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloud is a great reason to get to go to conferences! You need to provide the curiosity and justification for attending the training. Ask, and keep asking. When you do get to go to training, take the initiative to schedule time and share what you learned with your team. (It really helps when it comes time to ask to go again.)&lt;/p&gt;
&lt;h2 id="will-the-robots-take-my-job"&gt;Will the robots take my job?&lt;/h2&gt;
&lt;p&gt;Robots may take EVERYONE’s job. I can&amp;rsquo;t change that.&lt;/p&gt;
&lt;p&gt;However, I think as database people, we&amp;rsquo;re probably near the end of the list of jobs that will be replaced by Skynet. The robots need us to serve them until they are fully self-sustaining, and no longer need humans at all.&lt;/p&gt;
&lt;p&gt;But for the foreseeable future, there’s tons of work for data professionals to answer the question…&lt;/p&gt;
&lt;p&gt;“How do we get the most out of all this stuff?”&lt;/p&gt;
&lt;h2 id="my-1-advice-look-for-problems-you-want-to-solve-at-work-and-go-after-them"&gt;My #1 advice: Look for problems you &lt;em&gt;want&lt;/em&gt; to solve at work, and go after them&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/HangInThere-300x150.png" width="230"&gt;
&lt;/figure&gt;
Don&amp;rsquo;t get stuck on a job title. I did this at one point in my career, and it was a huge mistake. The job title “DBA” may disappear, or you might find you like a job with a different title.&lt;/p&gt;
&lt;p&gt;That’s fine. It’s not like “administrator” is a sexy term.&lt;/p&gt;
&lt;p&gt;You get one life. You may as well get to solve problems that you enjoy while you work. That&amp;rsquo;s way more important than how the HR department tries to classify you.&lt;/p&gt;</description></item><item><title>Understanding avg_total_user_cost and avg_user_impact in Missing Index Requests</title><link>https://kendralittle.com/2017/02/22/understanding-avg_total_user_cost-and-avg_user_impact-in-missing-index-requests/</link><pubDate>Wed, 22 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/22/understanding-avg_total_user_cost-and-avg_user_impact-in-missing-index-requests/</guid><description>&lt;p&gt;The hardest thing about looking at index requests in SQL Server is understanding what the column names mean.&lt;/p&gt;
&lt;h2 id="heres-a-simple-query-that-shows-missing-index-requests-for-a-database"&gt;Here&amp;rsquo;s a simple query that shows missing index requests for a database&lt;/h2&gt;
&lt;p&gt;When SQL Server optimizes a query, sometimes it guesses that an index might speed it up. A little green hint shows up in the execution plan for the query, and the information is recorded in the dynamic management views for the database&lt;/p&gt;
&lt;p&gt;You can get to the aggregate information with a query like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;statement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equality_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inequality_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;included_columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_total_user_cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_est_cost_of_requesting_plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_user_impact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_est_cost_reduction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_scans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_seeks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;times_requested&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_missing_index_groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_missing_index_group_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_group_handle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_handle&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_missing_index_details&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_handle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_handle&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But notice that I renamed some columns, and added others together.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s why.&lt;/p&gt;
&lt;h2 id="avg_total_user_cost-tells-you-how-expensive-sql-server-thought-the-queries-were-who-wanted-this-index"&gt;avg_total_user_cost tells you how &amp;ldquo;expensive&amp;rdquo; SQL Server thought the queries were who wanted this index&lt;/h2&gt;
&lt;p&gt;When SQL Server optimizes a query, it does a quick estimate of how much work it&amp;rsquo;s going to be. This is called the query&amp;rsquo;s &amp;ldquo;cost&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cost is &lt;em&gt;always&lt;/em&gt; an estimate in SQL Server. The cost isn&amp;rsquo;t updated after the query runs to reflect how expensive anything actually was. Even if you&amp;rsquo;re looking at an &amp;ldquo;actual&amp;rdquo; plan, the &amp;ldquo;actual&amp;rdquo; parts are just rowcounts.&lt;/p&gt;
&lt;p&gt;And &amp;ldquo;cost&amp;rdquo; isn&amp;rsquo;t a measurement of anything we&amp;rsquo;re familiar with, like seconds. I like to think of it as just &amp;ldquo;QueryBucks&amp;rdquo;, the weird currency of the SQL Server optimizer.&lt;/p&gt;
&lt;p&gt;The avg_total_user_cost column tells you whether SQL Server guessed that these queries were very cheap (say .0009 querybucks), or more expensive (say 500 querybucks).&lt;/p&gt;
&lt;p&gt;It doesn&amp;rsquo;t tell you anything about whether or not that guess was correct. The optimizer sometimes vastly under or over guesses cost.&lt;/p&gt;
&lt;p&gt;Hey, optimizin&amp;rsquo; ain&amp;rsquo;t easy! And it&amp;rsquo;s also got to get done &lt;em&gt;fast&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="avg_user_impact-tells-you-a-percentage-thatsql-server-guesses-the-index-would-reduce-that-estimated-cost"&gt;avg_user_impact tells you a percentage that SQL Server guesses the index would reduce that estimated cost&lt;/h2&gt;
&lt;p&gt;This column is a guess about a guess!&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say the query plan that SQL Server settled on for my query had an estimated cost of 500 querybucks. But SQL Server thought an index might make the query faster. It does a quick guess about &lt;em&gt;how much faster&lt;/em&gt; it will make.&lt;/p&gt;
&lt;p&gt;So if you see 99 for avg_user_impact, SQL Server thought that the index would drop the cost by 99%. Usually a high number like 99 in this column means that the query was scanning a large index, and the optimizer thought an index could allow it to do a very targeted seek operation instead.&lt;/p&gt;
&lt;h2 id="i-just-add-together-user_seeks-and-user_scans"&gt;I just add together user_seeks and user_scans&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not particularly meaningful to me whether the requesting query was doing a seek or a scan operation.&lt;/p&gt;
&lt;p&gt;It sounds like a big deal, but you can have a seek operation that actually looks at every row in the index. You can also have a scan operator that looks at only a few rows. (It may feed into a TOP operation that stops after just a couple of rows.)&lt;/p&gt;
&lt;p&gt;You can&amp;rsquo;t judge a book by it&amp;rsquo;s cover, and you can&amp;rsquo;t judge an index operation by its type.&lt;/p&gt;
&lt;p&gt;However, the combination of seeks+scans is an interesting number! That&amp;rsquo;s the number of times a query ran that SQL Server thinks user queries would have benefitted from this index.&lt;/p&gt;
&lt;h2 id="i-dont-rely-exclusively-on-the-missing-indexdmvs-for-good-reason"&gt;I don&amp;rsquo;t rely exclusively on the missing index DMVs, for good reason!&lt;/h2&gt;
&lt;p&gt;The missing index DMVs can give you a rough idea of the tables that may benefit most from index tuning, but you shouldn&amp;rsquo;t rely on them completely for designing indexes against a live database. The feature is just too limited.&lt;/p&gt;
&lt;p&gt;The missing index feature in SQL Server does NOT:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recommend key column order in an index (this is a big deal!)&lt;/li&gt;
&lt;li&gt;Make any recommendation for queries that qualify for &amp;rsquo;trivial&amp;rsquo; optimization - which means you could miss some dead simple opportunities to speed up frequent queries&lt;/li&gt;
&lt;li&gt;Suggest filtered indexes, clustered indexes, columnstore indexes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You don&amp;rsquo;t have to take my word for this - all of this is &lt;a href="https://technet.microsoft.com/en-us/library/ms345485.aspx"&gt;right in the documentation on the feature&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For this reason, I don&amp;rsquo;t make decisions about index tuning just from the missing index DMVs. I always look at top execution plans before making recommendations.&lt;/p&gt;</description></item><item><title>Adding Partitions to the Lower End of a Left Based Partition Function</title><link>https://kendralittle.com/2017/02/21/adding-partitions-to-the-lower-end-of-a-left-based-partition-function/</link><pubDate>Tue, 21 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/21/adding-partitions-to-the-lower-end-of-a-left-based-partition-function/</guid><description>&lt;p&gt;I recently got a table partitioning question from a reader:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We now need to load some historical data into the table for 2013 so I want to alter the function and schema to add monthly partitions for this. But I can&amp;rsquo;t work out how to do this using SPLIT? Every example and tutorial I&amp;rsquo;ve looked at shows how to add new partitions onto the end of a range, not split one in the middle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They sent along their partition function and scheme. It&amp;rsquo;s a LEFT based partition function, so the partitioning boundary points are &amp;ldquo;upper&amp;rdquo; boundaries. The partition function was set up using an INT data type with an interesting approach: they made the boundary points invalid dates, like 20161100.&lt;/p&gt;
&lt;p&gt;Basically, it looks something like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/partition-question-left-function-ints-need-more-partitions.png"&gt;
&lt;/figure&gt;
&lt;h2 id="there-are-a-few-approaches-you-could-take-here"&gt;There are a few approaches you could take here&lt;/h2&gt;
&lt;p&gt;In my diagram, I show that we have data starting in November, because I&amp;rsquo;m simplifying the problem. In reality, the person asking the question had data for 2014 through 2018, partitioned monthly. They needed to load historical data for 2013.&lt;/p&gt;
&lt;p&gt;You can choose to add partitions on the lower end of the existing table, and I&amp;rsquo;ll show you how. But you&amp;rsquo;ve got choices!&lt;/p&gt;
&lt;h3 id="option-add-another-partitioned-table-and-readboth-tables-through-a-partitioned-view"&gt;Option: add another partitioned table, and read both tables through a partitioned view&lt;/h3&gt;
&lt;p&gt;Partitioned tables with many billions of rows or hundreds of GB of data become unwieldy over time.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need to add a column? It must get added to all partitions. Literally, kind of a drag.&lt;/li&gt;
&lt;li&gt;Nonclustered indexes are the same across all partitions, unless you&amp;rsquo;re using filtered indexes. (Getting filtered indexes to get used is a whole &amp;rsquo;nother kind of drag.)&lt;/li&gt;
&lt;li&gt;Getting memory to create a large index over the whole table gets harder as it grows.&lt;/li&gt;
&lt;li&gt;Statistics are created per index or per column, not per-partition. Statistics have a maximum of ~200 rows, and it can be a little difficult to describe data distribution over 6 billion rows in a 200 step histogram sometimes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So in some environments, it&amp;rsquo;s better to have multiple partitioned tables, and use a partitioned view to simplify reading data. This frees you up to add new columns only to the &amp;ldquo;current&amp;rdquo; table, and index different tables as you need.&lt;/p&gt;
&lt;p&gt;Inserting data into partitioned views can be a bit of a pain, so many people taking this approach use dynamic SQL or a stored procedure to insert or update data into the &amp;ldquo;current&amp;rdquo; table, and the use the partitioned view for reads.&lt;/p&gt;
&lt;h3 id="option-take-a-different-approach-to-filegroups"&gt;Option: take a different approach to filegroups&lt;/h3&gt;
&lt;p&gt;On the one hand, it&amp;rsquo;s good to be consistent. On the other hand, do you really need one filegroup per month?&lt;/p&gt;
&lt;p&gt;Maybe you do for some reason.&lt;/p&gt;
&lt;p&gt;But maybe your SQL Server&amp;rsquo;s storage now uses some of that fancy automatic tiering, where less read data automatically goes to slower disks. So maybe the filegroups aren&amp;rsquo;t useful for performance anymore.&lt;/p&gt;
&lt;p&gt;And maybe you rebuild indexes in those filegroups, which results in having empty space in each filegroup&amp;hellip; and you could save some storage if you consolidated a bit.&lt;/p&gt;
&lt;p&gt;Filegroups can be useful for things like running CHECKDB against a subset of the data, and for restoring databases &amp;ldquo;piecemeal&amp;rdquo;. But depending on your storage and your data sizes, you might want to let several partitions of data (or maybe more) share a filegroup.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth thinking about before you finalize your scripts!&lt;/p&gt;
&lt;p&gt;(For the sake of the demo below, I stick with one partition per filegroup to be consistent with what they have.)&lt;/p&gt;
&lt;h2 id="oklets-fixour-partitions"&gt;OK, let&amp;rsquo;s fix our partitions!&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s really two things we want to fix here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The lowermost partition is assigned to the PRIMARY filegroup. It&amp;rsquo;s empty, which makes life fairly easy for us&amp;ndash; when we merge the 20161100 boundary point, the filegroup associated with that boundary point will be removed from the partition scheme. There&amp;rsquo;s no data to move in this case.&lt;/li&gt;
&lt;li&gt;After we get the PRIMARY filegroup out of our table, we need to add in new filegroups and partitions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I created a demo script over on GitHub that creates a database, then creates a partitioned table just like you see above. If you&amp;rsquo;d like to play along, &lt;a href="https://gist.github.com/LitKnd/90994d1148fc37792a336fc0aaf6daa0"&gt;grab the gist of the whole demo script here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="1-removing-the-primary-filegroup-from-our-partition-scheme"&gt;1. Removing the primary filegroup from our partition scheme&lt;/h3&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: If we were using RIGHT in our partition function or had data in that filegroup, there'd be more work to do to fix things up! Be very careful when merging or splitting boundary points in production. If you accidentally trigger data to move from one partition to another, that can be a very long, slow, painful process.
&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s no way to ALTER the filegroup an existing partition is assigned to. We can remove the boundary point associated with the filegroup, then add it back with the right filegroup, though. Since the partition is empty, this is no big deal in this case. All it takes is this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pf_monthly_int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MERGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20161100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-adding-in-new-filegroups-and-partitions"&gt;2. Adding in new filegroups and partitions&lt;/h3&gt;
&lt;p&gt;Adding new partitions is relatively simple. We need to add a new filegroup and file, tell the partition scheme to use that filegroup for the next partition we add, then do a &amp;lsquo;SPLIT&amp;rsquo; to add the boundary point.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code that makes that happen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* OK, let&amp;#39;s add that boundary point back and give it a non-primary FG */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Create the filegroup and give it a file... */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PartitionSplittin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;201610&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PartitionSplittin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FG201610&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;S:\MSSQL\Data\FG201610.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="n"&gt;MB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROWTH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="n"&gt;MB&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;201610&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Add the filegroup into the scheme by setting it NEXT USED */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ps_monthly_int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;201610&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Then we can SPLIT */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pf_monthly_int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SPLIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20161100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can repeat that same pattern to keep adding more partitions farther down the table, as far back as we need to go.&lt;/p&gt;
&lt;h2 id="how-can-i-tell-if-my-data-is-in-the-right-place"&gt;How can I tell if my data is in the right place?&lt;/h2&gt;
&lt;p&gt;I like to use the query &lt;a href="https://kendralittle.com/2017/01/31/which-filegroup-is-that-partition-using-how-many-rows-does-it-have/"&gt;here to verify everything looks right&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="best-practice-keep-empty-partitions-at-both-ends-of-your-table"&gt;Best practice: keep empty partitions at both ends of your table&lt;/h2&gt;
&lt;p&gt;You don&amp;rsquo;t have to take my word on this one. It&amp;rsquo;s right in Books Online on the &lt;a href="https://msdn.microsoft.com/en-us/library/ms186307.aspx"&gt;ALTER PARTITION FUNCTION article&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Always keep empty partitions at both ends of the partition range to guarantee that the partition split (before loading new data) and partition merge (after unloading old data) do not incur any data movement. Avoid splitting or merging populated partitions. This can be extremely inefficient, as this may cause as much as four times more log generation, and may also cause severe locking.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;ldquo;Severe locking&amp;rdquo; is about as much fun as it sounds, so always test ahead of time and be safe out there!&lt;/p&gt;</description></item><item><title>Confused by sp_who2 (Dear SQL DBA Episode 30)</title><link>https://kendralittle.com/2017/02/16/confused-by-sp_who2-dear-sql-dba-episode-30/</link><pubDate>Thu, 16 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/16/confused-by-sp_who2-dear-sql-dba-episode-30/</guid><description>&lt;p&gt;This week&amp;rsquo;s &amp;lsquo;Dear SQL DBA&amp;rsquo; question gets us down to the essentials: how to I tell if a transaction is hanging?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Recently, when I was checking if there are any hanging transactions in my database via &amp;ldquo;sp_who2 &amp;quot; procedure…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A transaction is &amp;ldquo;AWAITING COMMAND&amp;rdquo;&lt;/li&gt;
&lt;li&gt;LastBatch date is more than a week ago&lt;/li&gt;
&lt;li&gt;ProgramName is &amp;ldquo;SQLAgent - Generic Refresher&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Is the transaction hanging?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Learn the answer in this 15 minute video, or scroll down to read a written version of the answer.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/NuLLyxkOVtg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="lets-talk-about-sp_who2"&gt;Let&amp;rsquo;s talk about sp_who2&lt;/h2&gt;
&lt;p&gt;I started out using sp_who2, also! And I was often confused by sp_who2.&lt;/p&gt;
&lt;p&gt;sp_who2 is a built-in stored procedure in SQL Server.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shows a lot of sessions, even on an idle instance&lt;/li&gt;
&lt;li&gt;Doesn’t tell you much about what it’s doing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heres-what-an-idle-sql-server-looks-like-in-sp_who2"&gt;Here&amp;rsquo;s what an idle SQL Server looks like in sp_who2&lt;/h2&gt;
&lt;p&gt;This is my dev SQL Server instance. I have a few sessions open, but the only one which was executing anything was the one you see, where I ran sp_who2. I don&amp;rsquo;t have any agent jobs scheduled on this thing. It&amp;rsquo;s just waiting for something to happen.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s hard to know what to look at, because we see so much. And only 19 of the 49 sessions is on the screen, too.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/idle-sql-server-sp_who2-1024x561.png"&gt;
&lt;/figure&gt;
&lt;h2 id="scrolling-down-i-can-see-a-session-similar-to-the-one-our-question-is-about"&gt;Scrolling down, I can see a session similar to the one our question is about&lt;/h2&gt;
&lt;p&gt;Session 52 is a very similar case: it&amp;rsquo;s awaiting command, and it&amp;rsquo;s part of the SQL Server Agent.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sp_who2-something-similar-to-the-question-1024x297.png"&gt;
&lt;/figure&gt;
&lt;p&gt;I just started up my instance, so the &amp;ldquo;Last Batch&amp;rdquo; column isn&amp;rsquo;t long ago. But even if it&amp;rsquo;s more recent, can we tell if this is causing a problem? Does it have an open transaction?&lt;/p&gt;
&lt;h2 id="we-can-use-additional-old-school-commands-like-dbcc-inputbuffer-and-dbcc-opentran-to-find-out"&gt;We can use additional old school commands like DBCC INPUTBUFFER and DBCC OPENTRAN to find out&lt;/h2&gt;
&lt;p&gt;When I learned sp_who2, I also learned to use these two commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DBCC INPUTBUFFER (SPID) – what’s the last statement from the client? It returns only NVARCHAR(4000).&lt;/li&gt;
&lt;li&gt;DBCC OPENTRAN – what’s the oldest open transaction in a database?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And these commands work. They&amp;rsquo;re worth knowing about, just for times when they come up. (Foreshadowing: I&amp;rsquo;ll show you a better way than all of this soon.)&lt;/p&gt;
&lt;h2 id="dbcc-inputbuffer"&gt;DBCC INPUTBUFFER&lt;/h2&gt;
&lt;p&gt;I can plug the session id from the SQL Agent activity I saw in sp_who2 into this and get an idea of the last thing it ran.&lt;/p&gt;
&lt;p&gt;But wow, this is inconvenient when I have more than one thing I&amp;rsquo;m interested in! And also, I still don&amp;rsquo;t know if it has an open transaction or not.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbcc_inputbuffer-1024x251.png"&gt;
&lt;/figure&gt;
&lt;h2 id="dbcc-opentran"&gt;DBCC OPENTRAN&lt;/h2&gt;
&lt;p&gt;I saw in sp_who2 that session 52 was in the msdb database. I can run DBCC OPENTRAN and check what the oldest active transaction is. In this case it tells me that there&amp;rsquo;s no open transaction, so session 52 seems like it&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;That was a lot of steps, and it was pretty clunky.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/dbcc_opentran-1024x253.png"&gt;
&lt;/figure&gt;
&lt;h2 id="the-problem-isnt-you-the-problem-is-sp_who2-theres-a-better-way"&gt;The problem isn&amp;rsquo;t you. The problem is sp_who2. There&amp;rsquo;s a better way!&lt;/h2&gt;
&lt;p&gt;All the commands we&amp;rsquo;ve been talking about so far are from the SQL Server 2000 days. They&amp;rsquo;re old enough to drive.&lt;/p&gt;
&lt;p&gt;In SQL Server 2005, Microsoft gave us a better way to do these things. They gave us Dynamic Management Objects. (There are views and functions.)&lt;/p&gt;
&lt;p&gt;Microsoft regularly improves and updates the DMV queries. They&amp;rsquo;re awesome! Commands like sp_who2 and friends are still there for backwards compatibility.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Major pros to using Dynamic Management Objects: way more information&lt;/li&gt;
&lt;li&gt;Small downside: complex to write your own queries&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="meet-sp_whoisactive"&gt;Meet sp_WhoIsActive&lt;/h2&gt;
&lt;p&gt;That downside isn&amp;rsquo;t really a downside: &lt;a href="https://twitter.com/adammachanic?lang=en"&gt;Adam Machanic&lt;/a&gt; is a SQL Server expert, and he has a great free stored procedure that gives you all the DMV queries you need to see what&amp;rsquo;s running in your SQL Server.&lt;/p&gt;
&lt;p&gt;Free download: &lt;a href="http://whoisactive.com"&gt;whoisactive.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Right out of the gate, sp_WhoIsActive doesn’t show you the stuff you don&amp;rsquo;t need to worry about&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only shows you a ‘sleeper’ if it has an open transaction&lt;/li&gt;
&lt;li&gt;Unlike DBCC OPENTRAN, sp_WhoIsActive is instance level: you don’t have to run it per database&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sp_whoisactive-immediately-shows-that-my-idle-instance-has-nothin-goin-on"&gt;sp_WhoIsActive immediately shows that my idle instance has nothin&amp;rsquo; goin&amp;rsquo; on&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what my lazy dev instance looks like in sp_WhoIsActive:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sp_whoisactive-idle-instance-1024x216.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Nothing is actually running. It&amp;rsquo;s easy to see, and that&amp;rsquo;s great &amp;ndash; because when something &lt;em&gt;really is&lt;/em&gt; running, it makes it easy to see.&lt;/p&gt;
&lt;h2 id="we-can-see-sleepers-if-we-want--even-if-they-dont-have-an-open-transaction"&gt;We can see sleepers if we want &amp;ndash; even if they don&amp;rsquo;t have an open transaction&lt;/h2&gt;
&lt;p&gt;Sp_WhoIsActive has a boatload of parameters. If you want to see user processes who are sleeping and who don&amp;rsquo;t have an open transaction, use @show_sleeping_spids = 2.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/lazy-bums-1024x280.png"&gt;
&lt;/figure&gt;
&lt;p&gt;If we want to see the sql_text they ran, we can click on that column. No need to run DBCC INPUTBUFFER, it&amp;rsquo;s right there.&lt;/p&gt;
&lt;p&gt;And if we scroll to the right, we can see all sorts of things like the calling program, the status (sleeping in this case), and lots more info. It&amp;rsquo;s everything sp_who2 shows you, plus more.&lt;/p&gt;
&lt;h2 id="sleepers-are-usually-ok"&gt;Sleepers are usually OK&lt;/h2&gt;
&lt;p&gt;A sleeping session &lt;em&gt;without&lt;/em&gt; an open transaction&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Isn’t holding locks on a table&lt;/li&gt;
&lt;li&gt;Uses very little resources&lt;/li&gt;
&lt;li&gt;May be re-used by the application (by something like connection pooling)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-if-i-have-hundreds-or-thousands-of-sleepers"&gt;What if I have hundreds or thousands of sleepers?&lt;/h2&gt;
&lt;p&gt;I have seen a few cases where something was going wrong in connection pooling, and there were hundreds and hundreds of sleeping sessions. The longer the SQL Server was on, the more there would be.&lt;/p&gt;
&lt;p&gt;If these sessions were to become &lt;em&gt;active&lt;/em&gt; all at once, then things could go very badly, so it&amp;rsquo;s kind of creepy to find thousands of sleepers: it&amp;rsquo;s like looking out at a field of zombies. It&amp;rsquo;s worth addressing, and usually means connection pooling isn&amp;rsquo;t configured properly on the application servers.&lt;/p&gt;
&lt;p&gt;SQL Server does have a maximum number of connections, by the way: &lt;a href="https://msdn.microsoft.com/en-us/library/ms187030.aspx"&gt;32,767&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m getting a little far away from the question, which was about &lt;em&gt;one&lt;/em&gt; sleeping session.&lt;/p&gt;
&lt;h2 id="what-if-my-sleeperdoes-have-an-open-transaction"&gt;What if my sleeper &lt;em&gt;does&lt;/em&gt; have an open transaction?&lt;/h2&gt;
&lt;p&gt;I cover how to diagnose and treat “problem” sleepers who have open transactions in my new course, &lt;a href="course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;&amp;ldquo;Troubleshooting Blocking &amp;amp; Deadlocks for Beginners&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="thanks-to-adam-machanic-for-writing-sp_whoisactive-and-supporting-it-for-many-years"&gt;Thanks to Adam Machanic for writing sp_WhoIsActive and supporting it for many years!&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;If sp_WhoIsActive has helped you, tweet to &lt;a href="https://twitter.com/adammachanic?lang=en"&gt;@AdamMachanic&lt;/a&gt; and let him know&lt;/li&gt;
&lt;li&gt;Follow his blog at: &lt;a href="http://sqlblog.com/blogs/adam_machanic/"&gt;http://&lt;/a&gt;&lt;a href="http://sqlblog.com/blogs/adam_machanic/"&gt;sqlblog.com/blogs/adam_machanic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>The Top 3 Mistakes I Made Fighting Blocking</title><link>https://kendralittle.com/2017/02/16/the-top-3-mistakes-i-made-fighting-blocking/</link><pubDate>Thu, 16 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/16/the-top-3-mistakes-i-made-fighting-blocking/</guid><description>&lt;p&gt;At the beginning of the &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;&amp;ldquo;Troubleshooting Blocking and Deadlocks&amp;rdquo; course&lt;/a&gt;, I mention that it took me a long time to get into using the tools I show in the course.&lt;/p&gt;
&lt;p&gt;The tools are all free, and many of them are built into SQL Server.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: the &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;course&lt;/a&gt; itself is now free, too!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So why did it take me so long?&lt;/p&gt;
&lt;h2 id="1-i-was-using-outdated-built-incommands-to-troubleshoot-live-blocking"&gt;1. I was using outdated built-in commands to troubleshoot live blocking&lt;/h2&gt;
&lt;p&gt;Lots of us learn to use built-in tools from the SQL 2000 days and prior when we start using SQL Server. Things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sp_who2&lt;/li&gt;
&lt;li&gt;DBCC INPUTBUFFER&lt;/li&gt;
&lt;li&gt;DBCC OPENTRAN&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These commands are feast or famine: they either give you either more than you want, or not as much information as you need.&lt;/p&gt;
&lt;p&gt;These old commands haven&amp;rsquo;t been improved over the years by Microsoft for a very good reason: Microsoft gave us a much richer, more flexible set of tools when they introduced Dynamic Management Objects in SQL Server 2005, and they continue to improve the DMOs year after year. The old commands are still there for backwards compatibility.&lt;/p&gt;
&lt;p&gt;In the Blocking course, I demonstrate how you can make finding live blockers fast and easy by querying SQL Server dynamic management objects with the free sp_WhoIsActive procedure.&lt;/p&gt;
&lt;p&gt;This awesome free procedure is by Adam Machanic, and you can download it from &lt;a href="http://whoisactive.com/"&gt;http://whoisactive.com/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;People still learn old commands like sp_who2 first, and get confused. Just this week, I got a question for my Dear SQL DBA podcast about sp_who2 from someone who&amp;rsquo;s learning now. Here&amp;rsquo;s the &amp;lsquo;Dear SQL DBA&amp;rsquo; video where I show why sp_WhoIsActive makes life much less confusing:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/NuLLyxkOVtg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="2-i-pummeled-the-sql-server-looking-for-blocking-with-custom-scripts"&gt;2. I pummeled the SQL Server looking for blocking with custom scripts&lt;/h2&gt;
&lt;p&gt;Like a good DBA, I wanted to be proactively notified about blocking. Specifically, &lt;em&gt;before&lt;/em&gt; our customers notified me about the blocking.&lt;/p&gt;
&lt;p&gt;To do this, I wrote a bunch of TSQL that looked for blocked queries. And I ran it against the SQL Server. I ran it &lt;em&gt;A LOT&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This query alone wasn&amp;rsquo;t enough to bring down the SQL Server. But of course this wasn&amp;rsquo;t the only monitoring query I ran. There were more, and hilariously when you got to looking at what were the most expensive overall queries against the SQL Server&amp;hellip;&lt;/p&gt;
&lt;p&gt;Yeah, of course it was all those custom monitoring queries.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re troubleshooting a problem like &amp;ldquo;not enough CPU&amp;rdquo;, or you&amp;rsquo;re thinking about server sizing and CPU licensing comes to mind, you don&amp;rsquo;t really want to have the secret that the #1 CPU using queries against the instance are your monitoring queries.&lt;/p&gt;
&lt;p&gt;There are better ways! For blocking, I really like using a simple performance counter alert based on the &amp;ldquo;Processes Blocked&amp;rdquo; performance counter. It&amp;rsquo;s really easy to set up, it&amp;rsquo;s very lightweight. I show how to set this up in the course, along with other tools that will help you figure out who was blocking whom if you don&amp;rsquo;t get there until after the fact.&lt;/p&gt;
&lt;h2 id="3-i-thought-trace-flags-t1204-and-t1222-should-beenough-to-fix-deadlocks"&gt;3. I thought Trace Flags –T1204 and –T1222 should be enough to fix deadlocks&lt;/h2&gt;
&lt;p&gt;Trace flags 1204 and 1222 are well known in SQL Server. They&amp;rsquo;ve been around for a while. Each of these flags causes SQL Server to write information about a deadlock to the SQL Server Error Log when a deadlock occurs. One of them writes info in an XML format, the other just in text.&lt;/p&gt;
&lt;p&gt;I knew enough to enable these flags. And I&amp;rsquo;d see that deadlocks had happened.&lt;/p&gt;
&lt;p&gt;But I had no idea how to interpret the information, other than to be able to see little bits of the queries that were involved. I thought the problem was &lt;em&gt;me&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Well, maybe the problem was partly me, but it&amp;rsquo;s also really crappy to try to output a large wad of text information printed into an error log. It&amp;rsquo;s like trying to read a book in a foreign language where all the pages are out of order.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve found it much easier to collect and interpret deadlock graphs. There&amp;rsquo;s still a lot of complex information to synthesize: that&amp;rsquo;s the same. However, you get a graphic display of the problem, too. This helps you navigate around as you try to understand what&amp;rsquo;s going on.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also much easier when someone shows you how to decode the foreign language! So in the &lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;course&lt;/a&gt; I:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Give you code to generate a deadlock (and it&amp;rsquo;s rerunnable, no need to restore the database)&lt;/li&gt;
&lt;li&gt;Show you how to read the deadlock graph&lt;/li&gt;
&lt;li&gt;Give you tips on how to plan out solutions to prevent the deadlock from re-occurring&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>New online course: Troubleshooting Blocking &amp; Deadlocks for Beginners (Free!)</title><link>https://kendralittle.com/2017/02/14/new-online-course-troubleshooting-blocking-deadlocks-for-beginners/</link><pubDate>Tue, 14 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/14/new-online-course-troubleshooting-blocking-deadlocks-for-beginners/</guid><description>&lt;p&gt;I made y&amp;rsquo;all a SQL Server style Valentine&amp;rsquo;s day present: a new FREE online training course.&lt;/p&gt;
&lt;h2 id="course-info-troubleshooting-blocking--deadlocks-for-beginners"&gt;Course info: Troubleshooting Blocking &amp;amp; Deadlocks for Beginners&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Troubleshooting-Blocking-Deadlocking-1000-1000-with-Title-300x300.jpg" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;You need to prove if blocking is killing the performance on your SQL Server. Learn to set up simple, lightweight monitoring using free tools and scripts to find the queries causing your blocking and deadlock problems.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the course is laid out&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Welcome! Here’s what you need to get started (2 minutes)&lt;/li&gt;
&lt;li&gt;Wait stats, alerts, and troubleshooting blocking live (43 minutes)&lt;/li&gt;
&lt;li&gt;Troubleshooting blocking that happens when you’re away from your desk (31 minutes)&lt;/li&gt;
&lt;li&gt;Capture and prevent deadlocks (29 minutes)&lt;/li&gt;
&lt;li&gt;Interview questions (21 minutes)&lt;/li&gt;
&lt;li&gt;Learning plan (3 minutes)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lessons in these modules are each between 5 and 15 minutes on average, so you can easily move through the course in short sessions.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;Take this course for free&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-students-have-said-about-this-course"&gt;What students have said about this course&lt;/h2&gt;
&lt;p&gt;I gave an hour version of this course at the SQL PASS Summit in 2016. Here&amp;rsquo;s what students wrote in their session evaluations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;This session was hyper-approachable and gave me a lot of tools I can use to improve on a place I&amp;rsquo;m weak on.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Great Info and demos&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Moar dinosaurs! Excellent tips. Always great to find more free tools to help diagnose issues.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Speaker was excellent. Very knowledgeable. Learned a lot of very useful information that I can take back to the workplace. &amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;I&amp;rsquo;m well versed with blocking, deadlocking, and resolution.  This session was a good review of key points but still contained information that I hadn&amp;rsquo;t yet been aware of.  &amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The description of how to read a deadlock graph was one of the best I have ever heard.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Kendra was a delight to listen to.  She supplied useful information in an easy to learn fashion.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Kendra had some great examples of everything she was talking about. That helped a lot in learning how to deal with blocking and deadlocks.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;It was great to see something that I understood previously but from a different perspective. Everything was thoroughly explained and related in ways that made sense and painted a picture, literally there were pictures in the slides.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m getting a little choked up reading those comments&amp;ndash; man, what an awesome audience that was. Happy Valentines Day to me!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/course/troubleshooting-blocking-and-deadlocks-for-beginners/"&gt;Here&amp;rsquo;s the link again if you don&amp;rsquo;t feel like scrolling up.&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Should I Learn Fulltext Indexing? (Dear SQL DBA Episode 29)</title><link>https://kendralittle.com/2017/02/09/should-i-learn-fulltext-indexing-dear-sql-dba-episode-29/</link><pubDate>Thu, 09 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/09/should-i-learn-fulltext-indexing-dear-sql-dba-episode-29/</guid><description>&lt;p&gt;This week&amp;rsquo;s question is about a longstanding feature in SQL Server that sounds really cool: full-text search. If you&amp;rsquo;re learning performance tuning, how much time should you invest in researching and learning about full-text indexes?&lt;/p&gt;
&lt;p&gt;Watch this 18 minute video, or scroll on down to read the written scoop on full-text search.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/R9jwe8XOSE0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="dear-sql-dba"&gt;Dear SQL DBA&amp;hellip;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I have been doing performance tuning for about 9 months now. It puzzles me that one type of index never gets much attention: full text indexes. Are fulltext indexes a cool feature that can really help performance (all that LIKE &amp;lsquo;%blabla%&amp;rsquo; predicates application developers seem to love :-) ) or are they quite the opposite and not worth investing time in ?
Best regards,
Puzzled about fulltext&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &amp;ldquo;dirty little secret&amp;rdquo; about full-text search indexes is that they don&amp;rsquo;t help with &amp;lsquo;%blabla%&amp;rsquo; predicates.&lt;/p&gt;
&lt;p&gt;Well, it&amp;rsquo;s not a secret, it&amp;rsquo;s right there in the documentation.&lt;/p&gt;
&lt;p&gt;A lot of us get the impression that full-text search is designed to handle &amp;ldquo;full wildcard&amp;rdquo; searches, probably just because of the name. &amp;ldquo;Full-Text Searches&amp;rdquo; sounds like it means &amp;ldquo;All The Searches&amp;rdquo;. But that&amp;rsquo;s not actually what it means.&lt;/p&gt;
&lt;h2 id="what-is-full-text-searchgood-for"&gt;What is full-text search good for?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/full-text-not-indexed-300x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Full-text indexes can help with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prefix searches&lt;/strong&gt;. It&amp;rsquo;s good for &amp;lsquo;bla%&amp;rsquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phrases containing words&lt;/strong&gt;. So it&amp;rsquo;s good for &amp;lsquo;So blabla to you&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Different &lt;strong&gt;forms of a word&lt;/strong&gt; / synonyms (is there a synonym for blabla? I don&amp;rsquo;t know!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Words near one another&lt;/strong&gt; in a document (&amp;lsquo;bla&amp;rsquo; is in a document in proximity to &amp;lsquo;blop&amp;rsquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full-text search also has special features like &lt;a href="https://msdn.microsoft.com/en-us/library/ms142551.aspx"&gt;stoplists and stopwords&lt;/a&gt; to keep the index from becoming more bloated than it has to be, and help searches be more efficient.&lt;/p&gt;
&lt;p&gt;One way to think about this is that full-text search is designed to be smart about language: it thinks about phrases, synonyms, how words are used, things like that.&lt;/p&gt;
&lt;p&gt;A pure wildcard search of &amp;lsquo;%blabla%&amp;rsquo; isn&amp;rsquo;t really about language. That&amp;rsquo;s just looking for a pattern somewhere in a string.&lt;/p&gt;
&lt;p&gt;For wildcard searches and regular expression queries, secondary &lt;a href="https://lucene.apache.org/"&gt;applications like Lucene are attractive&lt;/a&gt;, and these days in the cloud there are options like Lucene Query in Azure Search.&lt;/p&gt;
&lt;h2 id="aside-azure-search-is-easy-to-play-with-for-free"&gt;Aside: Azure Search is easy to play with for free&lt;/h2&gt;
&lt;p&gt;A while back I wrote a post called &lt;a href="https://kendralittle.com/2016/10/25/wildcard-vs-regular-expressions-lucene-query-in-azure-search/"&gt;Wildcard vs Regular Expressions – Lucene Query in Azure Search&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It shows how easy it is to play around with texting non-sargable wildcard searches like &amp;lsquo;%blabla%&amp;rsquo; against online sample data in Azure. All you need is a browser, it&amp;rsquo;s totally free and you don&amp;rsquo;t even have to create an Azure account.&lt;/p&gt;
&lt;h2 id="fulltext-indexes-and-performance"&gt;Fulltext indexes and performance&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve run into quite a few companies using full-text search. Most of them were using it pretty lightly, and it rarely was something they asked me for help with: they set it up following the documentation, and it just worked. There were quite a few cases where I&amp;rsquo;d say something about seeing a full-text index when looking over an instance, and my client laughed and said they&amp;rsquo;d forgotten they even &lt;em&gt;used&lt;/em&gt; full-text. (If you think about it, that&amp;rsquo;s a compliment to the feature.)&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also run into some folks who&amp;rsquo;ve used full-text search so heavily that they pushed the boundaries of the feature: very large multi-terabyte databases pulling in large volumes of data.&lt;/p&gt;
&lt;h3 id="keeping-data-in-sync-with-heavy-update-rates"&gt;Keeping data in sync with heavy update rates&lt;/h3&gt;
&lt;p&gt;With heavy to ultra-heavy usage, one issue with full-text indexes is that they don&amp;rsquo;t update synchronously with the base table. This is helpful for performance for inserts, updates, deletes into the base table, because updating a large full-text index can take time. But it does mean that if your application allows both queries of the base table AND the full-text index, people could see different, contradictory data if the full-text index is behind.&lt;/p&gt;
&lt;h3 id="what-if-corruption-strikes"&gt;What if corruption strikes?&lt;/h3&gt;
&lt;p&gt;And as with any other index, you can get corruption in a full-text index. That&amp;rsquo;s not necessarily the SQL Server&amp;rsquo;s fault: corruption can come from the storage subsystem. If your full-text index gets corrupt, you&amp;rsquo;re probably going to have to rebuild it.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re working with giant full-text indexes, recreating the index can add up to a lot of downtime. Thinking about how your tables are laid out and breaking your indexes into manageable chunks becomes very important at scale.&lt;/p&gt;
&lt;h2 id="i-think-full-text-search-is-here-to-stay-its-just-getting-interesting-company"&gt;I think full-text search is here to stay, it&amp;rsquo;s just getting interesting company&lt;/h2&gt;
&lt;p&gt;This is an older feature, so there&amp;rsquo;s always that question as to how &amp;ldquo;fresh&amp;rdquo; it is.&lt;/p&gt;
&lt;p&gt;Microsoft has invested in making full-text indexes perform better over the years. The feature was revamped in 2008 and has received a variety of performance fixes over the years. A new DMV, sys.dm_fts_index_keywords_position_by_document , was a&lt;a href="https://msdn.microsoft.com/en-us/library/bb510411.aspx"&gt;dded in SQL Server 2016 and also backported to previous versions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Full-text search is well maintained by Microsoft. I don&amp;rsquo;t think it&amp;rsquo;s going anywhere.&lt;/p&gt;
&lt;h2 id="what-about-semantic-search"&gt;What about semantic search?&lt;/h2&gt;
&lt;p&gt;In SQL Server 2012, Microsoft added the &lt;a href="https://msdn.microsoft.com/en-us/library/gg492075.aspx"&gt;semantic search feature&lt;/a&gt; built on top of full-text search. Semantic search helps identify the main phrases in a document and can find and compare similar/related documents.&lt;/p&gt;
&lt;p&gt;Semantic is one of those features that dropped in and then seemed to disappear from the conversation, though.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t heard of its capabilities being strongly expanded in later versions, and I know people who evaluated it in SQL Server 2012 who found it to be too much of a &amp;ldquo;v1 feature&amp;rdquo; to fit their needs, compared to features offered by third-party vendors with semantic search tools.  (Of course, they were evaluating native semantic search because not everything was perfect with their third party app, either.)&lt;/p&gt;
&lt;p&gt;Here is one such investigation into semantic search by Joe Sack - &lt;a href="https://www.simple-talk.com/sql/database-administration/exploring-semantic-search-key-term-relevance/"&gt;Exploring Semantic Search Key Term Relevance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you use semantic search in production and know about improvements that I&amp;rsquo;m unaware of, I&amp;rsquo;d love to hear about it in the comments!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-much-time-should-you-invest-in-learning-full-text-indexes"&gt;How much time should you invest in learning full-text indexes?&lt;/h2&gt;
&lt;p&gt;To sum up, full-text indexing is &lt;em&gt;fairly&lt;/em&gt; widely used, but most of the folks using it are doing so on a small scale where it &amp;ldquo;just works.&amp;rdquo; Those companies are unlikely to have a high bar on full-text index skills when it comes to hiring, and they may not even ask you questions about it at all in a job interview.&lt;/p&gt;
&lt;p&gt;For most folks, I think it&amp;rsquo;s worth knowing the basic limitations of full-text and what the feature does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A one-time investment of an hour&lt;/strong&gt; to read and make notes for yourself is generally enough to get you to a point where you can identify potential use cases. If you ever find those use cases, at that point you can invest more time in evaluating how well full-text fits that implementation.&lt;/p&gt;
&lt;p&gt;After getting the big picture from this post, reading the &lt;a href="https://msdn.microsoft.com/en-us/library/ms142571.aspx"&gt;Books Online page on full-text search&lt;/a&gt; is probably good enough for most people. That&amp;rsquo;s where I&amp;rsquo;d spend the rest of your hour.&lt;/p&gt;
&lt;p&gt;After that, I wouldn&amp;rsquo;t invest a bunch of time learning about full-text indexes unless you&amp;rsquo;ve got a specific reason. You&amp;rsquo;re better off investing your time learning about wait statistics, tuning TSQL using execution plans, rowstore indexes, columnstore indexes, Query Store, and In-Memory indexes.&lt;/p&gt;
&lt;h2 id="some-fun-related-topics-building-your-own-type-of-full-text-index-and-querying-withregular-expressions"&gt;Some fun related topics: building your own type of full-text index, and querying with regular expressions&lt;/h2&gt;
&lt;p&gt;Aaron Bertrand writes about building your own word-part index: &lt;a href="https://sqlperformance.com/2017/02/sql-indexes/seek-leading-wildcard-sql-server"&gt;One way to get an index seek for a leading %wildcard&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dev Nambi created an &lt;a href="http://devnambi.com/2016/sql-server-regex/"&gt;open-source project, sql-server-regex&lt;/a&gt;, that uses the SQLCLR &amp;ldquo;lets you run regular expressions in T-SQL queries using scalar and table-valued functions.&amp;rdquo;  I know for a fact that Dev is crazy good at this stuff, because I worked with him for several years out there in the real world. He&amp;rsquo;s a unicorn.&lt;/p&gt;</description></item><item><title>Understanding Left vs. Right Partition Functions (with Diagrams)</title><link>https://kendralittle.com/2017/02/07/understanding-left-vs-right-partition-functions-with-diagrams/</link><pubDate>Tue, 07 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/07/understanding-left-vs-right-partition-functions-with-diagrams/</guid><description>&lt;p&gt;You&amp;rsquo;re designing table partitioning, or you want to make a change to an existing partition function. It&amp;rsquo;s critical to understand the difference between how &amp;ldquo;left&amp;rdquo; and &amp;ldquo;right&amp;rdquo; partition functions behave, but the documentation is a bit confusing on this topic.&lt;/p&gt;
&lt;p&gt;Honestly, even after years of working with partitioning, it&amp;rsquo;s easy to get confused about left and right after you think about something else for thirty seconds.&lt;/p&gt;
&lt;p&gt;This is explained in &lt;a href="https://msdn.microsoft.com/en-us/library/ms187802.aspx"&gt;Microsoft&amp;rsquo;s documentation&lt;/a&gt; with some tables. But for me, diagrams make this MUCH easier.&lt;/p&gt;
&lt;h2 id="left-based-partition-functions-use-upper-boundaries-and-all-boundaries-are-inclusive"&gt;&amp;ldquo;Left&amp;rdquo; based partition functions use upper boundaries, and all boundaries are inclusive&lt;/h2&gt;
&lt;p&gt;This is not as much fun as an all-inclusive resort. But know that boundary points are always &amp;ldquo;included&amp;rdquo; with a partition.&lt;/p&gt;
&lt;p&gt;Left based partitions are the default, if you don&amp;rsquo;t specify whether you want left or right. Here&amp;rsquo;s an example using a DATETIME2 data type with precision 7:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/partition-diagram-left-based-datetime2.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Left based partitioning can require being particularly nitpick-y if you&amp;rsquo;re working with the DATETIME or DATETIME2 data types. For example, if you&amp;rsquo;re partitioning by month, you typically don&amp;rsquo;t want the first moment of a month to be physically stored with data from the previous month&amp;ndash; so you have to specify the last second of the last hour of the last day of the month at the boundary point. (Related fact: DATETIME is peculiar because it &lt;a href="https://msdn.microsoft.com/en-us/library/ms187819.aspx"&gt;rounds microseconds to increments of 0, 3, and 7&lt;/a&gt;)&lt;/p&gt;
&lt;h2 id="right-based-partition-functions-use-lower-boundaries-also-inclusive"&gt;&amp;ldquo;Right&amp;rdquo; based partition functions use lower boundaries (also inclusive)&lt;/h2&gt;
&lt;p&gt;Right based partitions are simpler to define when it comes to DATETIME and DATE types, because every day begins at midnight and every month begins on the first.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/partition-diagram-right-based-datetime2.png"&gt;
&lt;/figure&gt;
&lt;h2 id="why-do-you-have-empty-partitions-in-those-diagrams"&gt;Why do you have empty partitions in those diagrams?&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a best practice to [keep the partitions at the ends of your table empty](&lt;a href="https://technet.microsoft.com/en-us/library/ms186307.aspx#Best"&gt;https://technet.microsoft.com/en-us/library/ms186307.aspx#Best&lt;/a&gt; Practices). This keeps your life simpler if you&amp;rsquo;re going to be adding (splitting) or removing (merging) partitions at the ends of your table.&lt;/p&gt;
&lt;h2 id="which-is-better-left-or-right"&gt;Which is better, left or right?&lt;/h2&gt;
&lt;p&gt;Honestly, I don&amp;rsquo;t have a huge preference these days. Either of them can be a big old pain if you mess up your boundary points, or let data &amp;ldquo;spill&amp;rdquo; into a location it shouldn&amp;rsquo;t because you forgot to keep empty partitions at the end of the table, particularly if you&amp;rsquo;re using a complex filegroup setup.&lt;/p&gt;
&lt;p&gt;So I recommend using whichever seems more straightforward for your data type and scenario. Just make sure that if you&amp;rsquo;re doing sliding window, or merging/splitting partitions for any reason, that you test all that code and make sure that you&amp;rsquo;re not accidentally causing data movement that will become painful when your data sizes grow.&lt;/p&gt;</description></item><item><title>Index Types: Heaps, Primary Keys, Clustered and Nonclustered Indexes (Dear SQL DBA Episode 28)</title><link>https://kendralittle.com/2017/02/02/index-types-heaps-primary-keys-clustered-and-nonclustered-indexes-dear-sql-dba-episode-28/</link><pubDate>Thu, 02 Feb 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/02/02/index-types-heaps-primary-keys-clustered-and-nonclustered-indexes-dear-sql-dba-episode-28/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I see HEAP tables are found even when I know those tables have a clustered index, and I see a lot of forwarded records. This happens to 5 tables in my database. I can see the clustered and in some ones the non-clustered indexes&amp;hellip; why are some scripts reporting them as heaps?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is an example of what I&amp;rsquo;m seeing from a script: &lt;br&gt;
dbo.AnonymousTable (0) [HEAP] [RID]  / 2,126,697 reads, 308,401 writes /  17,847 forwarded records fetched;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This puzzles a lot of people when they start working with indexes in SQL Server. The concepts here overlap and there are quite a few different ways you can do things.&lt;/p&gt;
&lt;p&gt;Watch the 27 minute video discussing this, or scroll on down to read a written version of the video, complete with code samples.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;Subscribe to the podcast&lt;/a&gt;, if you&amp;rsquo;d like to listen on the go! And a &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;review on iTunes&lt;/a&gt; will help others find out about the show.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/zfrfjporbmE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;First up, let&amp;rsquo;s clarify the concepts.&lt;/p&gt;
&lt;h2 id="concept-1--how-a-disk-basedtable-is-physically-ordered"&gt;Concept 1- How a disk-based table is physically ordered&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;I say &amp;ldquo;disk-based&amp;rdquo; because we&amp;rsquo;re not talking about in-Memory tables here. I&amp;rsquo;m not getting into those today for the sake of simplicity. (For a high level overview of disk-based vs in-Memory tables, &lt;a href="https://kendralittle.com/2016/07/05/which-indexes-are-disk-based-in-sql-server/"&gt;check out this post&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clustered Index&lt;/strong&gt;: This will always have IndexID = 1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clustered rowstore tables&lt;/strong&gt; - Traditional clustered index: you choose clustering key column(s) that determine the sort order of the data&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clustered columnstore tables&lt;/strong&gt; - Clustered columnstore indexes don&amp;rsquo;t have key columns. Every column in the table is stored in columnar format, which uses LOB (large-object) pages&lt;/p&gt;
&lt;p&gt;The syntax to create a clustered index may look like one of these samples:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* These samples create clustered indexes that are NOT also a primary key */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* 1. Two step process... */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusterMeToo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CX_ClusterMeToo_MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusterMeToo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* 2. Inline index create. This syntax works in SQL Server 2014+ */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusterMe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CX_ClusterMe_MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* 3. Clustered Columnstore Example. This exists in SQL Server 2014+ */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusteredColumnstore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CX_ClusteredColumnstore_MakeMeAClusteredIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may want your clustered index to &lt;em&gt;also&lt;/em&gt; be a primary key, in which case you want a different code sample. Keep reading!&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s a best practice to make rowstore indexes unique, but it&amp;rsquo;s not required.&lt;/li&gt;
&lt;li&gt;You can create a clustered columnstore index after the table has been created. You may even want to temporarily create a rowstore clustered index before you create the columnstore clustered index! Read the post, &amp;ldquo;&lt;a href="https://blogs.msdn.microsoft.com/sql_server_team/columnstore-index-performance-rowgroup-elimination/"&gt;Columnstore Index Performance: Rowgroup Elimination&lt;/a&gt;&amp;rdquo; from the SQL Server Tiger Team to learn more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Heap&lt;/strong&gt;: This will always have IndexID = 0&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you don&amp;rsquo;t define a clustered index, SQL Server uses a secret Row Identifier (RID) behind the scenes. You can&amp;rsquo;t use the RID in queries.&lt;/li&gt;
&lt;li&gt;You may have nonclustered indexes (rowstore or columnstore) on a heap. Those are secondary physical structures. They&amp;rsquo;ll always have an IndexID greater than 1, because that&amp;rsquo;s reserved for clustered indexes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The syntax to create a heap is something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HeapExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IMightBeAPK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* It remains a heap if you do NOT run any commands like this:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;CREATE [UNIQUE] CLUSTERED INDEX [index name] on [table name] ( [Column Name(s) ] or
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;ALTER TABLE [table name] ADD CONSTRAINT [constraint name] PRIMARY KEY CLUSTERED ( [Column Name(s)] )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;CREATE CLUSTERED COLUMNSTORE INDEX [index name] on [table name]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;*/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="concept-2--primary-key-the-column-or-columns-that-define-a-unique-row-for-business-purposes"&gt;Concept 2- Primary Key: the column or columns that define a unique row for business purposes&lt;/h2&gt;
&lt;p&gt;A table may have only &lt;em&gt;one&lt;/em&gt; primary key (PK). (You can enforce uniqueness in other ways with unique constraints and unique indexes, though.)&lt;/p&gt;
&lt;p&gt;A primary key is secretly an index! It can be clustered or nonclustered.&lt;/p&gt;
&lt;p&gt;Your primary key may technically be a &amp;ldquo;surrogate key&amp;rdquo;. That just means that it&amp;rsquo;s not a column that &amp;ldquo;naturally&amp;rdquo; identifies the data&amp;ndash; it may be an INT, BIGINT, or UNIQUEIDENTIFIER column that was designed to uniquely identify the row, even though the number or uniqueidentifier itself isn&amp;rsquo;t meaningful to look at.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clustered primary key&lt;/strong&gt;: This will always have IndexID = 1 (it&amp;rsquo;s a clustered index behind the scenes, as well as a constraint)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may choose to make the clustered index ALSO the primary key when you create the index / constraint. This means the column or columns that uniquely identify a row also define the physical sort order of the table on disk.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s no such thing as a clustered primary key on a clustered columnstore table. Clustered columnstore indexes don&amp;rsquo;t &lt;em&gt;have&lt;/em&gt; key columns&amp;ndash; every column in the table is stored in a columnar format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The syntax to create a clustered primary key can look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusteredPKExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MakeMeACXPK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_ClusteredPKExample_MakeMeACXPK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeMeACXPK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Or a two step create... */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnotherClusteredPKExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MakeMeACXPK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnotherClusteredPKExample&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_AnotherClusteredPKExample_MakeMeACXPK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeMeACXPK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Nonclustered primary key&lt;/strong&gt;: This will always have IndexID &amp;gt; 1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nonclustered primary key constraints are nonclustered indexes behind the scenes&lt;/li&gt;
&lt;li&gt;A nonclustered primary key may be created on a heap, or a table with a clustered index&lt;/li&gt;
&lt;li&gt;Antipattern: sometimes people create a clustered index and a non-clustered primary key on the same column or columns. This means your table has to maintain TWO indexes on the same key column, when you could just have one. It&amp;rsquo;s more efficient to create a clustered primary key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The syntax to create a nonclustered primary key may look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* 1. This syntax works in SQL Server 2014+ */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NonclusteredPKExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MakeMeCX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BusinessKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CX_NonclusteredPKExample_MakeMeCX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeMeCX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_NonclusteredPKExample_BusinessKey&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BusinessKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* 2. Three step create... */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnotherNonclusteredPKExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MakeMeCX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BusinessKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnotherNonclusteredPKExample&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_AnotherNonclusteredPKExample_BusinessKey&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BusinessKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cx_AnotherNonclusteredPKExample_MakeMeCX&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnotherNonclusteredPKExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MakeMeCX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* 3. Clustered Columnstore with PK, two step version.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;This works in SQL Server 2016+ */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusteredColumnstoreWithPKExample&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BusinessKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Col2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PK_ClusteredColumnstoreWithPKExample_BusinessKey&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BusinessKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cCx_ClusteredColumnstoreWithPKExample&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusteredColumnstoreWithPKExample&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="back-to-thequestion-what-happened"&gt;Back to the question: what happened?&lt;/h2&gt;
&lt;p&gt;Based on the initial email, I was pretty sure that the tables in question were accidentally created as heaps, each with a nonclustered primary key.&lt;/p&gt;
&lt;p&gt;The big giveaways were that indexid zero only ever exists on a heap, and forwarded records can also only occur in a heap object. In a brief email conversation back and forth, we confirmed that this was the case.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve run into this quite a few times in the wild. Sometimes the tables were a heap and someone later thought to add primary keys, and made them nonclustered without thinking. Sometimes people just accidentally use the wrong syntax at create time.&lt;/p&gt;
&lt;h2 id="which-type-of-indexes-should-i-use"&gt;Which type of indexes should I use?&lt;/h2&gt;
&lt;p&gt;In the case of our questioner, they likely want to just recreate their nonclustered primary keys and clustered primary keys. That&amp;rsquo;s kind of a pain if you&amp;rsquo;ve got a lot of foreign keys or SQL Server replication set up.&lt;/p&gt;
&lt;p&gt;While it&amp;rsquo;s generally a bad practice to have a unique clustered index and a non-clustered primary key on the same columns, because they&amp;rsquo;re duplicate indexes&amp;hellip; if the tables are small and don&amp;rsquo;t have a lot of modifications, I&amp;rsquo;m not going to pin a scarlet letter on you for doing it a few times.&lt;/p&gt;
&lt;p&gt;But for general use, let&amp;rsquo;s make some generalizations!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clustered primary key&lt;/strong&gt;: When the set of columns that uniquely identify a row are &lt;em&gt;also&lt;/em&gt; very frequently used in joins and the &amp;lsquo;where&amp;rsquo; clause of your query, ordering the table by those columns is usually a great fit. The clustered index automagically has direct access to all the in-row columns in a table without having to look it up in another structure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unique clustered index with a different nonclustered primary key (rowstore)&lt;/strong&gt;: Sometimes you have a table where it makes sense to physically sort the table on different columns than the ones that make up the primary key on the table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maybe the most important use of the table is range scan on a different column or columns and those queries access lots of columns in the table. Using that as the clustered index can be very powerful.&lt;/li&gt;
&lt;li&gt;Maybe the primary key is a very wide set of columns on a large table. Having a wide set of columns in the clustered index bloats all your nonclustered indexes (because it&amp;rsquo;s secretly added to them). Depending on how the table is queried, another column or set of columns may work better as the clustered index.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Heap tables&lt;/strong&gt; (possibly with a nonclustered PK, depending what you&amp;rsquo;re doing): You don&amp;rsquo;t always need a clustered index. Or any index for that matter. Heaps can have some weird problems, like those forwarded records, but that&amp;rsquo;s for another day. Heaps can be good for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tables that you always scan, where you want all the columns. Scanning heaps can be really fast!&lt;/li&gt;
&lt;li&gt;Tables that you query in a very specific, controlled, targeted manner which is suited to non-clustered indexes&lt;/li&gt;
&lt;li&gt;Staging tables where you&amp;rsquo;re doing quick and dirty loads and queries. Sometimes it&amp;rsquo;s faster to not create a clustered index, depending on what you&amp;rsquo;re doing. Test and use what performs best while making sure your data is valid: no shame in that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Columnstore indexes&lt;/strong&gt; (clustered and nonclustered): These are extremely powerful when you need to scan a lot of rows to do aggregations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data warehouse tables are the obvious fit here, and are where the feature started.
&lt;ul&gt;
&lt;li&gt;Since data warehouses are all about analytics and massive tables, the natural patterns are updatable clustered columnstore indexes, likely with table partitioning&lt;/li&gt;
&lt;li&gt;Whether you should use primary and foreign keys in your data warehouse is something people fight about. I accept people of all key choices here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OLTP databases can be a good fit, also!
&lt;ul&gt;
&lt;li&gt;Writeable nonclustered columnstore indexes are a big feature in SQL Server 2016, and are designed to help people with busy workloads which combine OLTP and analytic queries in the same database. That&amp;rsquo;s an increasingly common requirement: lots of businesses just cannot wait for an ETL to run before analysis.&lt;/li&gt;
&lt;li&gt;The natural pattern in an OLTP database using this would be a rowstore table with a Clustered PK and a nonclustered columnstore index on the columns you use for analytics&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Also in SQL Server 2016:
&lt;ul&gt;
&lt;li&gt;Optimistic locking (snapshot / RCSI) is supported against columnstore indexes&lt;/li&gt;
&lt;li&gt;You can read columnstore indexes on Availability Group secondaries (which automagically use snapshot behind the scenes)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Is my excitement for columnstore indexes in SQL Server 2016 showing?&lt;/p&gt;
&lt;h2 id="on-a-related-note"&gt;On a related note&amp;hellip;&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Pro-SQL-Server-Relational-Design-150x150.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Don&amp;rsquo;t be jealous, you can get one, too.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Sitting right next to me as I write this is the brand spanking new fifth edition of Louis Davidson&amp;rsquo;s Pro SQL Server Relational Database Design and Implementation, updated for SQL Server 2016. You can buy the book now from &lt;a href="http://www.apress.com/la/book/9781484219720"&gt;APress&lt;/a&gt; or &lt;a href="https://smile.amazon.com/Server-Relational-Database-Design-Implementation/dp/1484219724"&gt;Amazon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Those are not affiliate links and this is not a sponsored post. I&amp;rsquo;m just excited to read the fifth edition, and if you got this far in this post then you&amp;rsquo;d probably like it, too.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re in the process of modeling a SQL Server database, get Louis&amp;rsquo; book. It will help you along the way, and in designing future projects as well.&lt;/p&gt;</description></item><item><title>Which Filegroup is that Partition Using? How Many Rows Does It Have?</title><link>https://kendralittle.com/2017/01/31/which-filegroup-is-that-partition-using-how-many-rows-does-it-have/</link><pubDate>Tue, 31 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/31/which-filegroup-is-that-partition-using-how-many-rows-does-it-have/</guid><description>&lt;p&gt;Table Partitioning in SQL Server has a bit of a learning curve. It&amp;rsquo;s tricky to just figure out how much data you have and where the data is stored.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/partitioning-by-ikea-300x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;When you&amp;rsquo;re designing or managing partitioned tables, it&amp;rsquo;s useful to quickly verify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which tables are partitioned&lt;/li&gt;
&lt;li&gt;The type of partition function they use (left or right)&lt;/li&gt;
&lt;li&gt;Which boundary points are assigned to which filegroup&lt;/li&gt;
&lt;li&gt;How many rows and pages are in each partition (and which boundary point they&amp;rsquo;re associated with)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This helps make sure that you&amp;rsquo;re designing your tables correctly, and it also helps you avoid goofs like merging the wrong boundary point and causing a bunch of data to move into another&amp;ndash; which can be slow and painful.&lt;/p&gt;
&lt;p&gt;All this information is available in TSQL, it&amp;rsquo;s just an ugly query, and it doesn&amp;rsquo;t come in any built-in reports or views.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve got an ugly query for you!&lt;/p&gt;
&lt;h2 id="query-listing-partitioned-tables-with-boundary-point-filegroup-rowcount-partition-size-and-partition-number-by-index"&gt;Query listing partitioned tables with boundary point, filegroup, row count, partition size, and partition number by index&lt;/h2&gt;
&lt;p&gt;This query gives an overview of partitioned tables and indexes in a database.&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/1635ac3f5cf08b5f84c974ca4b5edf6a.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/1635ac3f5cf08b5f84c974ca4b5edf6a"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;
&lt;h2 id="column-definitions-and-notes"&gt;Column definitions and notes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Schema.Table&lt;/strong&gt;: Schema name concatenated with table name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Index ID&lt;/strong&gt;: Included for reference and ordering&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structure&lt;/strong&gt;: This will decode if it&amp;rsquo;s a partitioned heap, clustered index, nonclustered index, clustered columnstore index, or nonclustered columnstore index&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Index Name&lt;/strong&gt;: What it sounds like&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rows&lt;/strong&gt;: Number of rows in that partition&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In-Row GB&lt;/strong&gt;: Reserved in-row pages for that partition&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LOB GB&lt;/strong&gt;: Reserved LOB pages for that partition (reminder - columnstore indexes use LOB pages)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partition #&lt;/strong&gt;: This can be useful in some queries. Remember that &lt;a href="https://kendralittle.com/2016/06/07/merging-boundary-points-does-partition_number-changing-indicate-data-movement/"&gt;partition numbers are reassigned when you modify your partition function&lt;/a&gt; (split/merge)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partition Function Name&lt;/strong&gt;: The partition function is the &amp;ldquo;algorithm&amp;rdquo; that defines the boundary points for the partitions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Boundary Type&lt;/strong&gt;: Whether the boundary point is a &amp;ldquo;right&amp;rdquo; type (lower inclusive boundary) or a &amp;ldquo;left&amp;rdquo; type (upper inclusive boundary)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Boundary Point&lt;/strong&gt;: The value of the boundary point that goes with that particular partition&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filegroup&lt;/strong&gt;: Where the data is located (defined by the partition scheme)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="need-to-know-the-partition-scheme-name"&gt;Need to know the partition scheme name?&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s easy to add that column in &amp;ndash; sys.partition_schemes is already in the query. The partition scheme is what maps your partition function to the filegroups.&lt;/p&gt;
&lt;p&gt;In most cases, people just want to know where things currently are, so I left that out of the query.&lt;/p&gt;</description></item><item><title>What is that Garbage in my Execution Plan? (Dear SQL DBA Episode 27)</title><link>https://kendralittle.com/2017/01/26/whats-that-garbage-in-my-execution-plan-dear-sql-dba-episode-26/</link><pubDate>Thu, 26 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/26/whats-that-garbage-in-my-execution-plan-dear-sql-dba-episode-26/</guid><description>&lt;p&gt;Today I was working on some code samples for a user question, and I hit a weird roadblock.&lt;/p&gt;
&lt;p&gt;There was a bunch of garbage in my execution plan that I couldn&amp;rsquo;t explain. And by &amp;lsquo;garbage&amp;rsquo;, I mean a nested loop to a whole branch of code that I hadn&amp;rsquo;t asked SQL Server to run &amp;ndash; and a warning about an implicit conversion possibly causing problems with the quality of my execution plan.&lt;/p&gt;
&lt;p&gt;It took me a while to figure out the issue, and along the way I asked the following questions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Am I really querying a table, or am I accidentally querying a view? (It&amp;rsquo;s a table! I checked at least three times.)&lt;/p&gt;
&lt;p&gt;Is there some weird computed column in the table that I don&amp;rsquo;t know about? (Nope, nothing involved was a computed column, I checked that twice.)&lt;/p&gt;
&lt;p&gt;Am I awake right now? (Pinched myself, appeared awake. I have had weird dreams about SQL Server before, though.)&lt;/p&gt;
&lt;p&gt;Do I actually know anything about SQL Server? (Just about everyone has imposter syndrome sometimes.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Having gone through this checklist, I decided that I was awake, and that I could figure things out by looking through the execution plan carefully.&lt;/p&gt;
&lt;p&gt;Sure enough, calming down and stepping through the plan did the trick. Just like it always has.&lt;/p&gt;
&lt;p&gt;Watch the 18 minute video to find out the mysteries in this execution plan, or scroll on down to read about what I discovered.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/8Kc7fPpjc4E?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="heres-what-the-weirdness-looked-like"&gt;Here&amp;rsquo;s what the weirdness looked like&lt;/h2&gt;
&lt;p&gt;I was using the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters sample database&lt;/a&gt; from Microsoft. And I was running a stupid simple query.&lt;/p&gt;
&lt;p&gt;Stupid simple like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m selecting one column. There are no predicates at all. Sales.Customers is a normal old rowstore table, and CustomerName is nvarchar(100).&lt;/p&gt;
&lt;p&gt;For a query like this, I&amp;rsquo;d expect a very simple plan: an index seek or scan operator to pull back the data, and a SELECT operator.&lt;/p&gt;
&lt;p&gt;Instead, I saw an execution plan with 20 nodes, and a big old warning on the SELECT operator.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what it looked like in SQL Sentry Plan Explorer:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-Whats-That-Garbage.png"&gt;
&lt;/figure&gt;
&lt;p&gt;If you&amp;rsquo;d like to play along in a more interactive version, here&amp;rsquo;s the query over at &lt;a href="https://www.brentozar.com/pastetheplan/?id=By96OqUve"&gt;Paste the Plan&lt;/a&gt;. (The website view doesn&amp;rsquo;t show al the operator properties I&amp;rsquo;m going to talk about here, but you can grab the XML and use it in SSMS or Plan Explorer to see the detail if you&amp;rsquo;d like.)&lt;/p&gt;
&lt;p&gt;Hovering over the warning on the SELECT operator, here&amp;rsquo;s the warning (this is the tooltip from SSMS):&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-Whats-That-Garbage-warning-implicit-conversion.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Weird, it&amp;rsquo;s warning about the SalesTerritory column. I didn&amp;rsquo;t ask for it to do anything at all with SalesTerritory. Why is it doing a type conversion on that column?&lt;/p&gt;
&lt;h2 id="lets-start-at-the-top-right-of-the-query"&gt;Let&amp;rsquo;s start at the top right of the query&lt;/h2&gt;
&lt;p&gt;When I&amp;rsquo;m in doubt about an execution plan, I like to just start at the top right of the query plan and work my way through. I think of that top right operator as the &amp;ldquo;driver&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;In this case, it&amp;rsquo;s a clustered index scan of Sales.Customers. That makes sense: I asked for all the customer names. Hovering over that operator, though, there is something funny. When I look at the &amp;lsquo;output&amp;rsquo; columns, it is outputting not only CustomerName, but also DeliveryCityID!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-Whats-That-Garbage-Scan-Outputting-DeliveryCityID.png"&gt;
&lt;/figure&gt;
&lt;h2 id="so-whats-it-doing-with-deliverycityid"&gt;So what&amp;rsquo;s it doing with DeliveryCityID?&lt;/h2&gt;
&lt;p&gt;Moving one step to the left in the plan, there&amp;rsquo;s a nested loop operator. Hovering over that operator, it says that it outputs the CustomerName column to the select operator. (Good, because that&amp;rsquo;s what we asked for!)&lt;/p&gt;
&lt;p&gt;It also says that the Outer References for the nested loop are based on DeliveryCityID. OK, so it&amp;rsquo;s pulling back that column because it needs it to run the nested loop. We still don&amp;rsquo;t know why, but if we hunt around in that branch of the plan, maybe there&amp;rsquo;ll be a clue.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-Whats-That-Garbage-Nested-Loop-Outer-Reference-DeliveryCityID.png"&gt;
&lt;/figure&gt;
&lt;h2 id="at-this-point-i-started-hovering-over-operators-in-that-branch-of-the-plan"&gt;At this point, I started hovering over operators in that branch of the plan&lt;/h2&gt;
&lt;p&gt;As in life, when you&amp;rsquo;re lost in an execution plan, move around slowly and carefully, observe your surroundings, and look for your mom. I mean, look for inspiration.&lt;/p&gt;
&lt;p&gt;I could see that the query was pulling from the Cities and StateProvinces tables. And there were a bunch of filter operators as well.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-Whats-That-Garbage-Filters-Predicates.png"&gt;
&lt;/figure&gt;
&lt;p&gt;Here&amp;rsquo;s what the filters are doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is_rolemember(N&amp;rsquo;db_owner&amp;rsquo;)&amp;lt;&amp;gt;(0)&lt;/li&gt;
&lt;li&gt;is_rolemember([Expr1011]+N&amp;rsquo; Sales&amp;rsquo;)&amp;lt;&amp;gt;(0)&lt;/li&gt;
&lt;li&gt;[Expr1012]=session_context(N&amp;rsquo;SalesTerritory&amp;rsquo;)&lt;/li&gt;
&lt;li&gt;original_login()=N&amp;rsquo;Website&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="this-is-security-garbage-err-a-security-feature"&gt;This is &lt;em&gt;security&lt;/em&gt; garbage! Err&amp;hellip; a security feature!&lt;/h2&gt;
&lt;p&gt;Aha! This is a definite clue. Some sort of security wizardry has been applied to this table, so that when I query it, a bunch of junk gets tacked onto my query.&lt;/p&gt;
&lt;p&gt;I have no shame in admitting that I couldn&amp;rsquo;t remember at all what feature this was and how it works. A lot of security features were added in SQL Server 2016, and the whole point of a sample database like this to kick the tires of the features.&lt;/p&gt;
&lt;p&gt;I did a little remembering, and a little searching, and figured out that this is the Row Level Security feature (RLS) in SQL Server 2016.&lt;/p&gt;
&lt;h2 id="row-level-security-rls-adds-predicates-to-your-query-execution-plans"&gt;Row Level Security (RLS) adds predicates to your query execution plans&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s how row level security works. You create a table valued function that can be &amp;ldquo;inlined&amp;rdquo; (meaning merged) into your query execution plan. That function determines who can see the data.&lt;/p&gt;
&lt;p&gt;Then you create a &lt;a href="https://msdn.microsoft.com/en-us/library/dn765135.aspx"&gt;Security Policy&lt;/a&gt; for Row Level Security which defines when the table valued function will be applied to queries against a table.&lt;/p&gt;
&lt;p&gt;The whole point of Row Level Security is, actually, that it adds these predicates to your execution plans.&lt;/p&gt;
&lt;h2 id="how-do-i-tell-if-row-level-security-changed-my-plan"&gt;How do I tell if Row Level Security changed my plan?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a really easy way to tell if your plan was modified by RLS, I just didn&amp;rsquo;t know to look for it.&lt;/p&gt;
&lt;p&gt;Click on the &amp;lsquo;SELECT&amp;rsquo; operator in the plan and look down in the properties pane. If you see &amp;lsquo;SecurityPolicyApplied&amp;rsquo; = True, then parts of your execution plan may have come from a table valued function that Row Level Security added in.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-SecurityPolicyApplied.png"&gt;
&lt;/figure&gt;
&lt;h2 id="should-you-use-row-level-security"&gt;Should you use row level security?&lt;/h2&gt;
&lt;p&gt;Wellll&amp;hellip;. maybe. If you&amp;rsquo;re interested, read up on the possible loopholes in RLS as it stands now, and consider if those would impact you or not. Aaron Bertrand has a great article to get you started: read &lt;a href="https://www.mssqltips.com/sqlservertip/4005/sql-server-2016-row-level-security-limitations-performance-and-troubleshooting/"&gt;SQL Server 2016 Row Level Security Limitations, Performance and Troubleshooting&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="everyone-feels-dumb-looking-at-execution-plans-sometimes"&gt;Everyone feels dumb looking at Execution Plans sometimes&lt;/h2&gt;
&lt;p&gt;I look at plans a lot, and still, they had me questioning my sanity today. When I first started doing performance tuning in SQL Server, I understood so little about plans that I gave up pretty easily.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m really happy that I kept going, though. Because as confusing as they are, most of the time the answers you&amp;rsquo;re looking for are right there in the plan. Somewhere.&lt;/p&gt;
&lt;p&gt;Just keep swimming.&lt;/p&gt;</description></item><item><title>How to Find Queries Using an Index (and Queries Using Index Hints)</title><link>https://kendralittle.com/2017/01/24/how-to-find-queries-using-an-index-and-queries-using-index-hints/</link><pubDate>Tue, 24 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/24/how-to-find-queries-using-an-index-and-queries-using-index-hints/</guid><description>&lt;p&gt;Sometimes you know a query is out there, but it&amp;rsquo;s hard to find the exact query.&lt;/p&gt;
&lt;p&gt;SQL Server stores query execution plans in cache, but it can be difficult to query the XML it stores. And there&amp;rsquo;s always a chance that the query plan won&amp;rsquo;t be there, due to memory pressure, recompile hints, or the plan cache being cleared by setting changes or other administrative actions.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/the-land-of-lost-queries-1024x512.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I can&amp;rsquo;t guarantee that your query can always be in the plan cache. But I &lt;em&gt;can&lt;/em&gt; make it a bit easier to find the query you&amp;rsquo;re looking for.&lt;/p&gt;
&lt;p&gt;In this post I give example code to find queries using a specific index, or using an index hint. But you&amp;rsquo;ll find that it&amp;rsquo;s pretty easy to adapt these queries for whatever you&amp;rsquo;re looking for.&lt;/p&gt;
&lt;h2 id="how-i-like-to-search-the-plan-cache"&gt;How I like to Search the Plan Cache&lt;/h2&gt;
&lt;p&gt;If I&amp;rsquo;m looking in SQL Server&amp;rsquo;s Execution Plan Cache, I like to use the sys.dm_exec_text_query_plan dynamic management view. This stores those XML query plans as text.&lt;/p&gt;
&lt;p&gt;I learned about using this DMV from Grant Fritchey in his post, &amp;ldquo;&lt;a href="http://www.scarydba.com/2012/07/02/querying-data-from-the-plan-cache/"&gt;Querying the Plan Cache, Simplified&lt;/a&gt;.&amp;rdquo; Grant points out that while doing wildcard searches in the text version of a query plan isn&amp;rsquo;t fast, querying it as XML is often &lt;em&gt;even slower&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Things to remember when searching the plan cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Queries will be missing from the plan cache&lt;/li&gt;
&lt;li&gt;The larger your plan cache and the slower your CPUs, the longer this will take: handle with care&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="search-query-store-if-youve-got-it"&gt;Search Query Store, if You&amp;rsquo;ve Got It&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve enabled the SQL Server 2016+ Query Store on your databases, you&amp;rsquo;ve got something better to search than the plan cache. I&amp;rsquo;m including code to search Query Store as well.&lt;/p&gt;
&lt;h2 id="how-to-find-queries-using-a-specific-index"&gt;How to Find Queries Using a Specific Index&lt;/h2&gt;
&lt;h3 id="search-forqueries-in-the-execution-plan-cache"&gt;Search for queries in the execution plan cache&lt;/h3&gt;
&lt;p&gt;Simply plug the name of the index you&amp;rsquo;re looking for into this query. If you have multiple databases with the same index name, you&amp;rsquo;ll need to add additional criteria to get just the database you&amp;rsquo;re looking for.&lt;/p&gt;
&lt;p&gt;In many cases, this will return more queries than you&amp;rsquo;re looking for, because inserts and deletes will reference all nonclustered indexes on the table. You can either add additional predicates to this query, or just look through everything on the list, depending on what you&amp;rsquo;re doing.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Execution plan cache */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_start_offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_end_offset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATALENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_end_offset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_start_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_logical_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_logical_writes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creation_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_xml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_query_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_text_query_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_start_offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_end_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;textplan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_sql_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;textplan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%PK_Sales_Invoices%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="find-queries-using-the-index-in-query-store"&gt;Find queries using the index in Query Store&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s a starter query to get you going in Query Store when you&amp;rsquo;re looking to see who&amp;rsquo;s using an index.&lt;/p&gt;
&lt;p&gt;This query groups by the query_id and query_hash because Query Store records runtime stats for a query over multiple intervals.&lt;/p&gt;
&lt;p&gt;Similar to the previous query, just plug in the index name you&amp;rsquo;re looking for into the query plan text:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Query Store */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsqt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsqt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsqt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est_logical_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_writes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est_writes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ZONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pacific Standard Time&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_execution_time_PST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ZONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pacific Standard Time&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_execution_time_PST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum_compiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY_CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY_CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan_xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qpx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats_interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrsi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_interval_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qsrsi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_interval_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%PK_Sales_Invoices%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%query_store_runtime_stats%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Not a query store query */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%dm_exec_sql_text%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Not a query searching the plan cache */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est_logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="how-to-find-queries-using-an-index-hint-any-index-hint"&gt;How to Find Queries Using an Index Hint (*any* index hint)&lt;/h2&gt;
&lt;p&gt;Sometimes you just want to know if index hints are in play. If code is around hinting specific indexes, that means you need to be careful dropping or renaming those indexes&amp;ndash; or queries may fail.&lt;/p&gt;
&lt;h3 id="searchthe-execution-plan-cache-for-index-hints"&gt;Search the execution plan cache for index hints&lt;/h3&gt;
&lt;p&gt;To find forced indexes in the plan cache, look for plans that contain &amp;lsquo;%ForcedIndex=&amp;ldquo;1&amp;rdquo;%&amp;rsquo;, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Execution plan cache */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_start_offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_end_offset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATALENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_end_offset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_start_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_logical_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_logical_writes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creation_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plan_xml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_query_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_text_query_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_start_offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statement_end_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;textplan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_exec_sql_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;querystats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql_handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;textplan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%ForcedIndex=&amp;#34;1&amp;#34;%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPPER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%INDEX%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also specify that the text of the query needs to have the word &amp;lsquo;INDEX&amp;rsquo; in it (which is part of an index hint), to rule out false positives in the plan cache of queries running against system tables.&lt;/p&gt;
&lt;h3 id="find-index-hintsinquery-store"&gt;Find index hints in Query Store&lt;/h3&gt;
&lt;p&gt;To find forced indexes in Query Store, you can similarly look for plans with&amp;rsquo;%ForcedIndex=&amp;ldquo;1&amp;rdquo;%&amp;rsquo;, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Query Store */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsqt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_sql_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsqt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsqt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_text_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqltext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_reads&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est_logical_reads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_executions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avg_logical_io_writes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est_writes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ZONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pacific Standard Time&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_execution_time_PST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_execution_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ZONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pacific Standard Time&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_execution_time_PST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_compiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum_compiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY_CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRY_CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query_plan_xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qpx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_store_runtime_stats_interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsrsi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_interval_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qsrsi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime_stats_interval_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%ForcedIndex=&amp;#34;1&amp;#34;%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qsq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_hash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;est_logical_reads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Why You Should Switch in Staging Tables Instead of Renaming Them (Dear SQL DBA Episode 26)</title><link>https://kendralittle.com/2017/01/19/why-you-should-switch-in-staging-tables-instead-of-renaming/</link><pubDate>Thu, 19 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/19/why-you-should-switch-in-staging-tables-instead-of-renaming/</guid><description>&lt;p&gt;Over the years, I&amp;rsquo;ve come across a pattern fairly frequently: an application in an OLTP database periodically creates new tables, loads some data into them and fixes it up, then does a switcheroo and replaces old tables with the new tables.&lt;/p&gt;
&lt;p&gt;This can cause major problems with blocking if anyone else is querying the table.&lt;/p&gt;
&lt;h2 id="the-problem-looks-like-this"&gt;The problem looks like this&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Innocent query / queries are selecting from the current production table&lt;/li&gt;
&lt;li&gt;Switcheroo process comes along and tries to do an sp_rename&lt;/li&gt;
&lt;li&gt;Switcheroo process is blocked and is waiting on a schema modification lock&lt;/li&gt;
&lt;li&gt;Switcheroo process starts blocking EVVERRRYBODYYYY else who wants to query the table&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sometimes this clears quickly, but it varies depending on how long the queries take and how complex the Switcheroo process is. On a busy system, a big blocking backlog can even potentially cause THREADPOOL waits, which means the SQL Server generally feels like it&amp;rsquo;s not working for anyone.&lt;/p&gt;
&lt;p&gt;This is a tough problem, because you can&amp;rsquo;t get around it with isolation levels (even read uncommitted/nolock queries require a shared schema lock, which blocks a schema modification lock). You also can&amp;rsquo;t get around it with optimistic locking.&lt;/p&gt;
&lt;p&gt;In the past, I wrote that if you have to do this switcheroo, sp_rename is better than ALTER SCHEMA TRANSFER, &lt;a href="https://www.brentozar.com/archive/2015/05/staging-data-locking-danger-with-alter-schema-transfer/"&gt;but it still has a bunch of problems&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="today-a-little-light-bulb-went-on-there-is-a-better-way-to-do-this-than-to-use-sp_rename-if-you-have-existing-code-using-this-pattern"&gt;Today, a little light bulb went on. There is a better way to do this than to use sp_rename if  you have existing code using this pattern!&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you can avoid the &amp;lsquo;switcharoo&amp;rsquo; pattern altogether and simply create and manage multiple versions of your tables, and have your application use the latest version, that is best because it avoids the locking problem entirely. The trick in this post is for existing codebases where sp_rename or ALTER SCHEMA TRANSFER is already in use, and you need something to mitigate blocking problems in the short term.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a 12 minute video talking through the optional pattern. You can also scroll down below the video to read a written version of the solution. If you enjoy the video, you might like to &lt;a href="https://kendralittle.com/dearsqldba/"&gt;subscribe to the podcast&lt;/a&gt;. I would also love a &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;review on iTunes&lt;/a&gt;!&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/HAP7XLasNFk?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="this-pattern-works-in-sql-server-2014-and-higher-and-it-even-works-in-standard-edition-of-2014"&gt;This pattern works in SQL Server 2014 and higher. And it even works in Standard Edition of 2014.&lt;/h2&gt;
&lt;p&gt;Some folks will see the word &amp;lsquo;Switch&amp;rsquo; in this pattern and assume the pattern that I&amp;rsquo;m suggesting is Enterprise Edition only for versions before SQL Server 2016 SP1.&lt;/p&gt;
&lt;p&gt;However, oddly enough, you can use partition switching even in Standard Edition, as long as the tables only have &lt;strong&gt;one&lt;/strong&gt; partition.&lt;/p&gt;
&lt;p&gt;And all rowstore tables have at least one partition! That happens automagically when you create a table.&lt;/p&gt;
&lt;h2 id="heres-the-pattern-use-switch-partition-withwait_at_low_priority"&gt;Here&amp;rsquo;s the pattern: Use SWITCH PARTITION with WAIT_AT_LOW_PRIORITY&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;d like to play around with this in full, I&amp;rsquo;ve got a &lt;a href="https://gist.github.com/LitKnd/11543b08b5b97ad9588d44dbc6f2047f"&gt;big old code sample in a gist for you to use on your test instance&lt;/a&gt;. But here&amp;rsquo;s the part that contains the magic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductionTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SWITCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductionTableOld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WAIT_AT_LOW_PRIORITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_DURATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MINUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ABORT_AFTER_WAIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BLOCKERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--Anyone who tries to query the table after the switch has happened and before
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--the transaction commits will be blocked: we&amp;#39;ve got a schema mod lock on the table
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StagingTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SWITCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductionTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Some notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For Standard Edition below SQL Server 2016 SP1, the syntax is a little different: ALTER TABLE dbo.ProductionTable SWITCH TO dbo.ProductionTableOld;  (Thanks to Ben for pointing this out in the comments!)&lt;/li&gt;
&lt;li&gt;The reason this solution helps is that WAIT_AT_LOW_PRIORITY won&amp;rsquo;t cause the big blocking chain behind it if this gets blocked. It will sit by the side MUCH more gracefully, even if it can&amp;rsquo;t get a schema modification lock. (Here&amp;rsquo;s &lt;a href="https://blogs.msdn.microsoft.com/saponsqlserver/2014/01/17/new-functionality-in-sql-server-2014-part-3-low-priority-wait/"&gt;a Microsoft post that goes into a lot of detail about wait at low priority&lt;/a&gt; - if you want the nitty gritty.)&lt;/li&gt;
&lt;li&gt;This also helps because you get to pick how long it waits, and what it does after that time is up. In this sample I say to kill off the blockers. That&amp;rsquo;s not going to be a good choice all the time: maybe you&amp;rsquo;d like it to just sit there waiting at low priority, or to give up itself. You get the choice.&lt;/li&gt;
&lt;li&gt;You probably do want to use an explicit transaction with this, unless it&amp;rsquo;s OK that someone queries the table while it&amp;rsquo;s empty, between the switching. And if that&amp;rsquo;s the case, you&amp;rsquo;d want the WAIT_AT_LOW_PRIORITY options on the second switch.&lt;/li&gt;
&lt;li&gt;This only works when the tables are in the same filegroup. Otherwise it wouldn&amp;rsquo;t be a metadata only change.&lt;/li&gt;
&lt;li&gt;You have to create matching indexes on your staging table and production table to make the switching work. (But you were doing that work before you renamed the new table in, anyway.) I kept the &lt;a href="https://gist.github.com/LitKnd/11543b08b5b97ad9588d44dbc6f2047f"&gt;sample gist&lt;/a&gt; super simple, but you can add indexes to that if you want to see it in action.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-if-i-want-to-truncate-the-data-instead-of-switching-it-out"&gt;What if I want to truncate the data, instead of switching it out?&lt;/h2&gt;
&lt;p&gt;The TRUNCATE TABLE command doesn&amp;rsquo;t have the WAIT_AT_LOW_PRIORITY option. Using it would put you right back in your big old blocking chain problem. A DELETE statement will be logged and also has blocking problems.&lt;/p&gt;
&lt;p&gt;Instead, you can use the SWITCH pattern above, and then just immediately truncate dbo.ProductionTableOld. As long as that table isn&amp;rsquo;t being read by anyone, you don&amp;rsquo;t have a blocking problem truncating it.&lt;/p&gt;
&lt;h2 id="anyone-think-this-is-a-terrible-idea"&gt;Anyone think this is a terrible idea?&lt;/h2&gt;
&lt;p&gt;There could well be something I&amp;rsquo;m missing about this solution. Happy to hear about it in the comments if you see a problem!&lt;/p&gt;</description></item><item><title>Bug: Incorrect modification_counter for Column Stats on Tables with a Clustered Columnstore Index</title><link>https://kendralittle.com/2017/01/17/bug-incorrect-modification_counter-for-column-stats-on-tables-with-a-clustered-columnstore-index/</link><pubDate>Tue, 17 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/17/bug-incorrect-modification_counter-for-column-stats-on-tables-with-a-clustered-columnstore-index/</guid><description>&lt;p&gt;I don&amp;rsquo;t find bugs in SQL Server all that often. I find bugs in my own code &lt;em&gt;all the time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In this case I double checked, and I think it&amp;rsquo;s a real SQL Server bug.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/bug-pablo-150x150.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;In SQL Server 2016 SP1, I see an issue with how SQL Server tracks and reports on modifications to column statistics on tables with a clustered columnstore index: it reports more modifications than actually occurred (and for columns that weren&amp;rsquo;t modified). The modification counter is useful for knowing &lt;a href="https://kendralittle.com/2016/12/06/when-did-sql-server-last-update-that-statistic-how-much-has-been-modified-since-and-what-columns-are-in-the-stat/"&gt;approximately how much has changed since statistics were last updated&lt;/a&gt;.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: I only see this issue when the table has a clustered columnstore index. Things look normal when the table has a nonclustered columnstore index, or no columnstore index at all.
&lt;/div&gt;
&lt;h2 id="please-vote-up-my-bug-for-visibility"&gt;Please vote up my bug for visibility&lt;/h2&gt;
&lt;p&gt;Even if you&amp;rsquo;re not using clustered columnstore indexes yet, they&amp;rsquo;ll probably be in your future before long. After all, as of SQL Server 2016 SP1, you can now use these sweet babies &lt;a href="https://kendralittle.com/2016/11/16/sql-server-2016-sp1-features-added-to-standard-web-express-local-db-editions/"&gt;in Standard Edition&lt;/a&gt;. (YES!)&lt;/p&gt;
&lt;p&gt;Do Future You a favor and take a moment to &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/3118876/modification-counter-incorrect-for-all-column-stats-on-table-with-clustered-columnstore-index"&gt;vote up my bug so it gets reviewed, and hopefully fixed if Microsoft confirms the issue&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="code-free-description-of-this-bug"&gt;Code-free description of this bug&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the set up &amp;ndash; a simple table with a clustered columnstore index, and several column statistics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a table with several columns&lt;/li&gt;
&lt;li&gt;Populate it with rows&lt;/li&gt;
&lt;li&gt;Create a clustered columnstore index on it&lt;/li&gt;
&lt;li&gt;Run some queries with predicates to create column level stats on individual columns&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;modification_counter&lt;/code&gt; for column statistics using a query that joins to &lt;code&gt;sys.dm_db_stats_properties&lt;/code&gt; (at this point, they will be 0)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The test is simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update one column for a single row&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;modification_counter&lt;/code&gt; for column statistics using a query that joins to &lt;code&gt;sys.dm_db_stats_properties&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Expected outcome: &lt;code&gt;modification_counter&lt;/code&gt; should be 1 for a single column statistic (or it should be NULL for all column statistics if this simply isn&amp;rsquo;t supported on tables with clustered columnstore indexes)&lt;/p&gt;
&lt;p&gt;Actual outcome: &lt;code&gt;modification_counter&lt;/code&gt; is 2 for ALL column statistics&lt;/p&gt;
&lt;h2 id="repro-code"&gt;Repro code&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve created &lt;a href="https://gist.github.com/LitKnd/f8bcf317b3fc4aa9fa3b8dbf1216915d"&gt;a gist with code to create a simple database and table and reproduce the bug&lt;/a&gt;. (This is the same code attached to the connect item.)&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/f8bcf317b3fc4aa9fa3b8dbf1216915d.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/f8bcf317b3fc4aa9fa3b8dbf1216915d"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>How to Query Histogram Target XML in Extended Events</title><link>https://kendralittle.com/2017/01/12/how-to-query-histogram-target-xml-in-extended-events/</link><pubDate>Thu, 12 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/12/how-to-query-histogram-target-xml-in-extended-events/</guid><description>&lt;p&gt;When I was recently &lt;a href="https://kendralittle.com/2017/01/03/parallelism-and-tempdb-data-file-usage-in-sql-server/"&gt;testing tempdb file usage&lt;/a&gt;, I used an Extended Events session that used SQL Server&amp;rsquo;s histogram target to track sqlserver.file_read events in the tempdb database for a specific session.&lt;/p&gt;
&lt;p&gt;I like using the histogram target because it&amp;rsquo;s relatively lightweight &amp;ndash; you can &amp;ldquo;bucket&amp;rdquo; results by what you&amp;rsquo;re interested in. In my case, I was interested seeing the cumulative number of file_read events by file name.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s one problem: the histogram target is stored in memory, not in a data file. If you want to query that data and store it off in a table, it&amp;rsquo;s not obvious how to do that.&lt;/p&gt;
&lt;h2 id="my-xevents-session-and-a-test-query"&gt;My XEvents Session and a test query&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the TSQL for the extended events session that I used for my research:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SESSION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tempdb&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EVENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collect_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;equal_uint64&lt;/span&gt;&lt;span class="p"&gt;]([&lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="p"&gt;],(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sqlserver&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TARGET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;histogram&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filtering_event_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sqlserver.file_read&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;source_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENT_RETENTION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALLOW_SINGLE_EVENT_LOSS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;MAX_DISPATCH_LATENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAX_EVENT_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MEMORY_PARTITION_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TRACK_CAUSALITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;STARTUP_STATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(You&amp;rsquo;re probably using a totally different event, and that&amp;rsquo;s fine &amp;ndash; I&amp;rsquo;m just including the definition of the trace I used as an example.)&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that I want to see which tempdb files have file_read events for the following query, which I run in a session with the SPID 53:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="what-the-data-looks-like-in-the-ssms-gui"&gt;What the data looks like in the SSMS Gui&lt;/h2&gt;
&lt;p&gt;I can access the results easily in the GUI. I just have to click on the histogram target under the Extended Events session:&lt;/p&gt;
&lt;p&gt;![histogram-target-extended-events]&lt;/p&gt;
&lt;p&gt;This opens a tab in SSMS, which shows that my query mostly used one tempdb file&amp;hellip; but there was one file_read event for another file:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Histogram-data-GUI-SSMS.png"
alt="histogram-data-gui-ssms"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Please don&amp;rsquo;t tell anyone that I put my tempdb files on my system drive on this test instance, it&amp;rsquo;s my dirty little secret.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The GUI is nice, but If I&amp;rsquo;m running a series of tests, it&amp;rsquo;s much easier to query this data with TSQL and record it to a table.&lt;/p&gt;
&lt;h2 id="querying-the-histogram-target-with-tsql"&gt;Querying the Histogram Target with TSQL&lt;/h2&gt;
&lt;p&gt;The data for this is stored in XML. You could store the results as XML, but personally, I&amp;rsquo;d rather go ahead and shred it so I can read the results in a table.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the query that I used to get this data via TSQL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(value)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;varchar(256)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(@count)[1]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;varchar(256)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slotcount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_session_targets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xet&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_xe_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_session_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tempdb-test&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;histogram&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;//HistogramTarget/Slot&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slot_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the results look like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/TSQL-XEvents-Histogram-Target.png"
alt="tsql-xevents-histogram-target"&gt;
&lt;/figure&gt;
&lt;p&gt;Voila, the same data we saw in the GUI!&lt;/p&gt;
&lt;h2 id="want-to-learn-more-about-the-histogram-target"&gt;Want to learn more about the Histogram Target?&lt;/h2&gt;
&lt;p&gt;Check out &lt;a href="http://jasonbrimhall.info/2015/10/22/histograms-and-events/"&gt;this blog post by Jason Brimhall&lt;/a&gt;, where he gives an example of using the histogram target to see which databases are experiencing deadlocks. He uses slightly different queries to pull from the histogram target, so you can pick the queries you like the best.&lt;/p&gt;</description></item><item><title>Administering COTS databases (ISVs / Third Party Vendors)</title><link>https://kendralittle.com/2017/01/10/administering-cots-databases-isvs-third-party-vendors/</link><pubDate>Tue, 10 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/10/administering-cots-databases-isvs-third-party-vendors/</guid><description>&lt;p&gt;I recently received a question from a vendor about databases created by software vendors.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/COTS-database-holidays.png"
alt="cots-database-holidays" width="230"&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;I just moved from an in-house software development company to a new environment that most of the software used here are COTS (Commercial off-the-shelf)&lt;/p&gt;
&lt;p&gt;This is totally new to me. I&amp;rsquo;m a little bit lost since I don&amp;rsquo;t know anything on the applications, users (security), or the schema. What is your recommendation to manage such an environment and perform performance tuning?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="part-of-the-confusion-is-terminology"&gt;Part of the confusion is terminology&lt;/h2&gt;
&lt;p&gt;I hadn&amp;rsquo;t heard the acronym &amp;ldquo;COTS&amp;rdquo; before &amp;ndash; but that doesn&amp;rsquo;t surprise me.  Companies have wildly different terms they use for this. If you manage these types of databases, you many need to use multiple search terms to find more resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Third party vendor database / application&lt;/li&gt;
&lt;li&gt;Independent Software Vendor database / application (ISV)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And also COTS!&lt;/p&gt;
&lt;h2 id="heres-a-great-article-on-administeringcots-databases-fordbas"&gt;Here&amp;rsquo;s a great article on administering COTS databases for DBAs&lt;/h2&gt;
&lt;p&gt;Tim Ford wrote a terrific article for this - it just doesn&amp;rsquo;t come up if you search for &amp;ldquo;COTS SQL Server&amp;rdquo;, because he used the term &amp;ldquo;third party&amp;rdquo; in the heading. But it&amp;rsquo;s terrific advice, and it covers a ton of bases:&lt;/p&gt;
&lt;p&gt;Read &lt;a href="http://sqlmag.com/database-administration/17-questions-every-sql-dba-should-ask-supporting-new-third-party-database"&gt;17 Questions Every SQL DBA Should Ask Before Supporting a New Third-Party Database&lt;/a&gt; by &lt;a href="https://twitter.com/sqlagentman"&gt;Tim Ford&lt;/a&gt; over on SQLMag.com.&lt;/p&gt;
&lt;h2 id="what-about-performance-tuning-these-databases"&gt;What about Performance Tuning these databases?&lt;/h2&gt;
&lt;p&gt;Some additional questions I ask when getting to know a COTS environment is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How important is performance for each application &amp;ndash; &lt;em&gt;ranked by the users&lt;/em&gt;.  Performance tuning can be time consuming, and this will help you prioritize and focus your efforts.
&lt;ul&gt;
&lt;li&gt;List out all the applications and ask users to rank how important performance is for them where one is highest and one is lowest (no ties for rank)&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ll need to figure out the name of the applications and how they map to the database names to do this (often they are different). That&amp;rsquo;ll come in VERY handy for you down the road when someone reports that &amp;ldquo;the Zebra app is slow&amp;rdquo;, so it&amp;rsquo;s totally worth it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Which vendors let you create non-clustered indexes in the databases, and which don&amp;rsquo;t? Index tuning is a major tool, and some vendors don&amp;rsquo;t mind if you add non-clustered indexes, but some forbid it.
&lt;ul&gt;
&lt;li&gt;First, I&amp;rsquo;d check if I have documentation from the vendor and if it covers this. If it doesn&amp;rsquo;t tell you, I&amp;rsquo;d ask the vendor.&lt;/li&gt;
&lt;li&gt;Even if a vendor says &amp;ldquo;no indexes allowed&amp;rdquo;, if you hit a case where an index fixes a major performance problem when run against a restored backup of the database where you made the change, you can bring it up again with them then. Sometimes &amp;ldquo;no&amp;rdquo; turns into &amp;ldquo;just this once.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Which vendors let you create plan guides in the databases, and which don&amp;rsquo;t? Plan guides are like duct tape for query plans &amp;ndash; they can help you change a behavior when you can&amp;rsquo;t change the query itself.
&lt;ul&gt;
&lt;li&gt;Many vendors may not know what a plan guide is and react with &amp;ldquo;what?&amp;rdquo; to this question.&lt;/li&gt;
&lt;li&gt;If you do create plan guides without permission, make sure to remove them before running any upgrade scripts. Not that I suggested you do that ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does the vendor make suggestions for parallelism settings, or other SQL Server configuration settings?
&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t assume that the suggestions are being honored on the instance. It&amp;rsquo;s worth checking what the vendor recommends, comparing it to existing settings, and investigating if it is different&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does the vendor forbid you from turning on Query Store (SQL Server 2016+)?
&lt;ul&gt;
&lt;li&gt;Honestly, I wouldn&amp;rsquo;t even ask this question straight out &amp;ndash; I&amp;rsquo;d review the vendor documentation and just see if turning on Query Store is explicitly forbidden. If it&amp;rsquo;s not forbidden, I&amp;rsquo;d enable Query Store. If it is forbidden, I&amp;rsquo;d ask why.&lt;/li&gt;
&lt;li&gt;Query Store is a little different from a schema change like creating indexes &amp;ndash; you should be careful about plan freezing / pinning on sensitive vendor databases, but I can&amp;rsquo;t think of a reason why a vendor wouldn&amp;rsquo;t allow you to turn this on. It&amp;rsquo;s basically like asking, &amp;ldquo;Can I monitor this database?&amp;rdquo; Generally, yes, absolutely.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When performance tuning COTS databases (aka third party databases), I use &lt;a href="https://kendralittle.com/2016/06/02/dear-sql-dba-lost-in-performance-troubleshooting/"&gt;the same performance tuning methodology&lt;/a&gt; I do for other databases &amp;ndash; but I know that re-writing the queries is typically a last resort as a fix, as it&amp;rsquo;s something I&amp;rsquo;d need to request from the vendor which may take a very long time to roll out (if it happens at all).&lt;/p&gt;</description></item><item><title>Configure Fields and Predicates for Multiple X-Events</title><link>https://kendralittle.com/2017/01/05/configure-fields-and-predicates-for-multiple-x-events/</link><pubDate>Thu, 05 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/05/configure-fields-and-predicates-for-multiple-x-events/</guid><description>&lt;p&gt;I&amp;rsquo;m not always the best at learning to use graphical interfaces. Maybe that&amp;rsquo;s why I often don&amp;rsquo;t like them?&lt;/p&gt;
&lt;h2 id="the-discovery"&gt;The Discovery&lt;/h2&gt;
&lt;p&gt;I do rather like the Extended Events GUI &amp;ndash; at least better than I like writing my own TSQL for Extended Events. And I finally figured out something that wasn&amp;rsquo;t obvious to me at all: it&amp;rsquo;s very easy to set global fields and predicates for multiple events!&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an animated GIF showing the magic of highlighting multiple events using the shift key:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/PJsKtNgynBbw73EDc9/source.gif"
alt="extended-events-configure-multiple-events"&gt;
&lt;/figure&gt;
&lt;p&gt;Was this obvious to everyone else?&lt;/p&gt;
&lt;p&gt;It only took me a few years to figure it out. :smile:&lt;/p&gt;</description></item><item><title>Parallelism and tempdb data file usage in SQL Server</title><link>https://kendralittle.com/2017/01/03/parallelism-and-tempdb-data-file-usage-in-sql-server/</link><pubDate>Tue, 03 Jan 2017 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2017/01/03/parallelism-and-tempdb-data-file-usage-in-sql-server/</guid><description>&lt;p&gt;I’m sometimes asked if the number of CPU cores used by a query determines the number of tempdb files that the query can use.&lt;/p&gt;
&lt;p&gt;Good news: even a single threaded query can use multiple tempdb data files.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Baguettes-tempdb-files-france-300x300.png"
alt="baguettes-tempdb-files-france" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="first-tempdb-is-a-tricksy-place"&gt;First, tempdb is a tricksy place!&lt;/h2&gt;
&lt;p&gt;My first version of this post used a flawed methodology: I configured an instance of SQL Server 2016 with four equally sized, small tempdb files. I then tested a set of queries that qualify for parallelism alternately using 4 processors, and running them single threaded (using option maxdop 1 as a query hint).&lt;/p&gt;
&lt;p&gt;I observed that the queries always made all four files grow.&lt;/p&gt;
&lt;p&gt;However, in that first version of the post, I forgot that the default behavior in SQL Server 2016 is to grow &lt;em&gt;all&lt;/em&gt; files in tempdb simultaneously when one grows. Basically, one small feature of SQL Server 2016 is that trace flag 1117 is always enabled by default for tempdb. Just because all the data files grew doesn&amp;rsquo;t mean they all got used!&lt;/p&gt;
&lt;p&gt;(For more on tempdb behavior changes in SQL Server 2016, &lt;a href="https://blogs.sentryone.com/aaronbertrand/sql-server-2016-tempdb-fixes/"&gt;read Aaron Bertrand&amp;rsquo;s post here&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="can-we-just-turn-off-tf-1117-for-tempdb"&gt;Can we just turn off TF 1117 for tempdb?&lt;/h2&gt;
&lt;p&gt;For most databases, you can control whether all the files in a filegroup grow at once by changing a setting on the filegroup.&lt;/p&gt;
&lt;p&gt;But not tempdb. If you run this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tempdb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MODIFY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTOGROW_SINGLE_FILE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You get the error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 5058, Level 16, State 12, Line 1
Option &amp;lsquo;AUTOGROW_SINGLE_FILE&amp;rsquo; cannot be set in database &amp;rsquo;tempdb&amp;rsquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="lets-use-science-otherwise-known-as-extended-events"&gt;Let&amp;rsquo;s use science. Otherwise known as Extended Events.&lt;/h2&gt;
&lt;p&gt;I admit: I didn&amp;rsquo;t do this in the first place because it was a bunch of work. The devil is in the detail with stuff like this. A lot of events seem like they&amp;rsquo;d work, but then you try to use them and either you don&amp;rsquo;t get the data you&amp;rsquo;d expect, or the trace generates such a massive amount of data that it&amp;rsquo;s hard to work with.&lt;/p&gt;
&lt;h2 id="i-used-the-sqlserverfile_read-event-and-a-histogram-target"&gt;I used the sqlserver.file_read event and a histogram target&lt;/h2&gt;
&lt;p&gt;I love the histogram target because it &lt;em&gt;doesn&amp;rsquo;t&lt;/em&gt; generate a huge file of data to confuse myself with. I set up my new test this way&amp;hellip;&lt;/p&gt;
&lt;p&gt;Extended Events trace for sql server.file_read&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Collect file paths (just to make it easy to see the data file names)&lt;/li&gt;
&lt;li&gt;filter on database_id=2 (tempdb)&lt;/li&gt;
&lt;li&gt;filter on session_id = 57 (the session I happened to be testing under)&lt;/li&gt;
&lt;li&gt;The histogram target was set to &amp;ldquo;bucket&amp;rdquo; file_read by each file path&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I set up a bunch of queries in a batch, and for each query:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Dumped everything out of memory (ran a checkpoint in tempdb and dbcc dropcleanbuffers)&lt;/li&gt;
&lt;li&gt;Ran a short waitfor in case the checkpoint took a bit of time&lt;/li&gt;
&lt;li&gt;Started the trace&lt;/li&gt;
&lt;li&gt;Ran the query&lt;/li&gt;
&lt;li&gt;Dumped the data from the histogram into a table&lt;/li&gt;
&lt;li&gt;Stopped the trace (this clears the histogram)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I ran the whole thing a couple of times to make sure I got consistent results. And I did!&lt;/p&gt;
&lt;h2 id="results-single-threaded-queries-can-use-multiple-tempdb-data-files"&gt;Results: single threaded queries CAN use multiple tempdb data files&lt;/h2&gt;
&lt;p&gt;One of my queries does a large sort operation. Using maxdop 4 and maxdop 1, it still evenly used my tempdb data files.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/sort-operator-multiple-tempdb-files.png"
alt="sort-operator-multiple-tempdb-files"&gt;
&lt;/figure&gt;
&lt;p&gt;I saw similar patterns with a query using a merge join, a query using a lazy spool, and a query with a sort that was engineered to be under-estimated (and has a memory spill).&lt;/p&gt;
&lt;h2 id="results-queries-may-not-use-tempdb-filesin-the-same-ways"&gt;Results: queries may not use tempdb files in the same ways&lt;/h2&gt;
&lt;p&gt;As you might guess, things may not always get evenly accessed, even if you have evenly sized tempdb files. One of my queries did a select into a temp table. Although it used all four tempdb files whether or not it went parallel, there were more file_read events against the first tempdb file than against the other four.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/multiple-tempdb-files-different-access-patterns.png"
alt="multiple-tempdb-files-different-access-patterns"&gt;
&lt;/figure&gt;
&lt;h2 id="could-my-methodology-still-have-problems"&gt;Could my methodology still have problems?&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s possible. I haven&amp;rsquo;t used the sqlserver.file_read event much, or tested it super thoroughly. It seemed to give me consistent results.&lt;/p&gt;
&lt;p&gt;So while it&amp;rsquo;s possible that I&amp;rsquo;ll suddenly realize that there&amp;rsquo;s a better way to measure this, I think at least my results are better than they were the first time I wrote this post!&lt;/p&gt;</description></item><item><title>Columnstore Indexes and Computed Columns in SQL Server 2016</title><link>https://kendralittle.com/2016/12/29/columnstore-indexes-and-computed-columns-in-sql-server-2016/</link><pubDate>Thu, 29 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/29/columnstore-indexes-and-computed-columns-in-sql-server-2016/</guid><description>&lt;p&gt;You can&amp;rsquo;t do everything with a columnstore index &amp;ndash; but SQL Server&amp;rsquo;s optimizer can get pretty creative so it can use a columnstore index in ways you might not expect.&lt;/p&gt;
&lt;h2 id="you-cant-put-a-computed-column-in-a-columnstore-index"&gt;You can&amp;rsquo;t put a computed column in a columnstore index&lt;/h2&gt;
&lt;p&gt;If you try to create a nonclustered columnstore index on a computed column, you&amp;rsquo;ll get error message 35307:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 35307, Level 16, State 1, Line 270&lt;/p&gt;
&lt;p&gt;The statement failed because column &amp;lsquo;BirthYear&amp;rsquo; on table &amp;lsquo;FirstNameByBirthDate_1976_2015&amp;rsquo; is a computed column. Columnstore index cannot include a computed column implicitly or explicitly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="but-sql-server-may-still-decide-to-use-a-columnstore-index-for-a-query-specifying-a-computed-column"&gt;But SQL Server may still decide to use a Columnstore index for a query specifying a computed column!&lt;/h2&gt;
&lt;p&gt;I went ahead and created a nonclustered columnstore index on the other columns in my table, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col_dbo_FirstNameByBirthDate_1976_2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1976_2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDateId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I ran this query against the table, which groups rows by the computed column, BirthYear:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1976_2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BETWEEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2001&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at the execution plan, SQL Server decided to scan the non-clustered columnstore index, even though it doesn&amp;rsquo;t contain the computed column BirthYear! This surprised me, because I have a plain old non-clustered index on BirthYear which covers the query as well. I guess the optimizer is &lt;em&gt;really&lt;/em&gt; excited about that nonclustered columnstore.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/NonClustered-Columnstore-Index-Scan-Actual-Plan-1024x81.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The columnstore index isn&amp;rsquo;t the best choice for this query:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duration using nonclustered rowstore index on computed BirthYear: &lt;strong&gt;2.722 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Duration using nonclustered columnstore index: &lt;strong&gt;5.5 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wheres-birthyear-lets-look-at-the-compute-scalar-farthest-to-the-right"&gt;Where&amp;rsquo;s BirthYear? Let&amp;rsquo;s look at the Compute Scalar farthest to the right&lt;/h2&gt;
&lt;p&gt;Clicking on that compute scalar operator and looking at the properties window, we can see that SQL Server looked up the definition for the computed column, and figured out that the computation is based on columns in our nonclustered index&amp;ndash; so it could scan that index, then run the computation for each row.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Compute-Scalar-Operator-Defined-Values.jpg"
alt="compute-scalar-operator-defined-values"&gt;
&lt;/figure&gt;
&lt;p&gt;SQL Server is waiting until the third operator, a filter, to filter out the rows for BirthYear between 2001 and 2015:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Execution-Plan-First-Three-Steps.jpg"
alt="execution-plan-first-three-steps"&gt;
&lt;/figure&gt;
&lt;h2 id="the-cost-estimate-on-that-compute-scalar-is-waaaayyy-low"&gt;The cost estimate on that Compute Scalar is waaaayyy low&amp;hellip;&lt;/h2&gt;
&lt;p&gt;This is an actual execution plan, so I have &lt;a href="https://kendralittle.com/2016/12/20/actual-time-statistics-in-execution-plans-elapsed-cpu-time-and-more/"&gt;Actual Time Statistics&lt;/a&gt;, and I can see exactly how much CPU was burned to compute BirthYear for every row. Scrolling up in the properties window, I find that this took almost five seconds for each thread that worked on the compute scalar. That&amp;rsquo;s more than 80% of the query&amp;rsquo;s duration just to figure out BirthYear.&lt;/p&gt;
&lt;p&gt;Oops!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Compute-Scalar-Operator-actual-time-statistics-1.jpg"
alt="compute-scalar-operator-actual-time-statistics"&gt;
&lt;/figure&gt;
&lt;h2 id="i-can-rewrite-my-query-a-bit-to-push-that-filter-down"&gt;I can rewrite my query a bit to push that filter down&amp;hellip;&lt;/h2&gt;
&lt;p&gt;My original query has the predicate, &lt;code&gt;BirthYear BETWEEN 2001 and 2015&lt;/code&gt;. Let&amp;rsquo;s change that predicate to a non-computed column:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NameCount&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByBirthDate_1976_2015&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2001-01-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATETIME2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FakeBirthDateStamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATETIME2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BirthYear&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m still using the computed column BirthYear in my SELECT and GROUP BY.&lt;/p&gt;
&lt;p&gt;SQL Server still chooses the columnstore index for this query, but now there is a predicate on the columnstore index scan itself:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/predicate-on-columnstore-index-scan.jpg"
alt="predicate-on-columnstore-index-scan"&gt;
&lt;/figure&gt;
&lt;p&gt;This means far fewer rows are flowing into the compute scalar operator &amp;ndash; we don&amp;rsquo;t have to calculate BirthYear for any of the rows from 1976 through the end of 2000.&lt;/p&gt;
&lt;h2 id="sure-enough-its-faster"&gt;Sure enough, it&amp;rsquo;s faster&lt;/h2&gt;
&lt;p&gt;Making this change to the query text makes our nonclustered columnstore index highly competitive with Ye Olde covering rowstore b-tree index:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duration using nonclustered rowstore index on computed BirthYear: &lt;strong&gt;2.722 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Duration using nonclustered columnstore index with original query: &lt;strong&gt;5.5 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Duration using nonclustered columnstore index with predicate re-written to not reference computed column: &lt;strong&gt;2.2 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we couldn&amp;rsquo;t re-write the predicate easily for whatever reason, we might choose to keep the non-clustered rowstore index on BirthYear around and use &lt;code&gt;OPTION (IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX)&lt;/code&gt; in our query.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/matrix-95-percent-computed-columns-300x300.png"
alt="matrix-95-percent-computed-columns" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="be-careful-with-computed-columns-and-columnstore"&gt;Be careful with computed columns and columnstore&lt;/h2&gt;
&lt;p&gt;I had assumed the optimizer would be reluctant to create a plan for a computed column, since that column can&amp;rsquo;t be in the columnstore index. But it turned out to be pretty eager to do it.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve got computed columns and are testing out columnstore, look carefully at your queries and check to make sure you don&amp;rsquo;t have any super-expensive compute scalar operators showing up in your plans where you might not want them.&lt;/p&gt;
&lt;h2 id="vote-to-allow-computed-columns-in-columnstore-indexes"&gt;Vote to allow computed columns in columnstore indexes&lt;/h2&gt;
&lt;p&gt;Wouldn&amp;rsquo;t this all be easier if you could just put the computed column in the columnstore, anyway? &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/1860102"&gt;Vote up this Connect item&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Tracing Deadlock Graphs: Extended Events or Server Side Trace</title><link>https://kendralittle.com/2016/12/27/tracing-deadlock-graphs-extended-events-or-server-side-trace/</link><pubDate>Tue, 27 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/27/tracing-deadlock-graphs-extended-events-or-server-side-trace/</guid><description>&lt;p&gt;Deadlock graphs are incredibly helpful for figuring out why queries are getting automatically killed off by SQL Server.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Deadlock-Manager-SQL-Server-300x300.png"
alt="deadlock-manager-sql-server" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="the-challenge"&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;But it can be tricky to trace deadlocks in SQL Server. You might be tempted to use Profiler, but the application has lots of baggage. You&amp;rsquo;re better off using either Extended Events (which may be confusing), or a Server Side Trace (which you can script from Profiler&amp;ndash; if you know exactly which buttons to push in the right order). You might look in the System Health trace on recent versions of SQL Server, but if the deadlock didn&amp;rsquo;t happen recently, then it may have rolled off the trace.&lt;/p&gt;
&lt;h2 id="the-solution"&gt;The Solution&lt;/h2&gt;
&lt;p&gt;To make this all easier, I&amp;rsquo;ve created a gist on GitHub sharing TSQL to save you a bunch of time.&lt;/p&gt;
&lt;h2 id="script-options"&gt;Script Options&lt;/h2&gt;
&lt;p&gt;Choose the script that works for you. You can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a simple Extended Events trace to get deadlock graphs via the sqlserver.xml_deadlock_report event&lt;/li&gt;
&lt;li&gt;Use a Server Side SQL Trace to get deadlock graphs (for older versions of SQL Server, or people who like SQL Trace)&lt;/li&gt;
&lt;li&gt;Use a (much more verbose) Extended Events trace to get errors, completed statements, and deadlock graphs. You only need something like this if the input buffer showing in the deadlock graph isn&amp;rsquo;t enough, and you need to collect the other statements involved in the transactions. You do this by matching the transaction id for statements to the xactid for each item in the Blocked Process Report. &lt;em&gt;Warning, this can generate a lot of events and slow performance.&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/LitKnd/19a5942e2527af3e90692c5145c3a059"&gt;View or download the code from GitHub&lt;/a&gt;, or get it below.&lt;/p&gt;
&lt;p&gt;When testing out these deadlock traces, you might want &lt;a href="https://kendralittle.com/2016/09/13/deadlock-code-for-the-wideworldimporters-sample-database/"&gt;code to reproduce a deadlock in SQL Server&lt;/a&gt;.&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/19a5942e2527af3e90692c5145c3a059.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/19a5942e2527af3e90692c5145c3a059"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>Collecting the Blocked Process Report (XEvents and Server Side Trace)</title><link>https://kendralittle.com/2016/12/22/collecting-the-blocked-process-report-xevents-and-server-side-trace/</link><pubDate>Thu, 22 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/22/collecting-the-blocked-process-report-xevents-and-server-side-trace/</guid><description>&lt;p&gt;I&amp;rsquo;m a big fan of the built-in Blocked Process Report in SQL Server. It&amp;rsquo;s come in handy for troubleshooting blocking situations for me many times.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/unblocked-clean-up-300x300.png"
alt="unblocked-clean-up" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I wanted a friendly way to share code to configure and manage the Blocked Process Report, so I&amp;rsquo;ve created a gist on GitHub sharing TSQL that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enables the Blocked Process Report (BPR)&lt;/li&gt;
&lt;li&gt;Collects the BPR with an Extended Events trace&lt;/li&gt;
&lt;li&gt;Collects the BPR using a Server Side SQL Trace (in case you don&amp;rsquo;t care XEvents or are running an older version of SQL Server)&lt;/li&gt;
&lt;li&gt;Lists out the Extended Events and SQL Traces you have running, and gives you code to stop and delete traces if you wish&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/LitKnd/f93c10a00d01d0f4ba00b84d9ac72e1b"&gt;View or download the code from GitHub&lt;/a&gt;, or get it below.&lt;/p&gt;
&lt;h2 id="tools-to-help-decode-theblocked-process-report-afteryou-collect-it"&gt;Tools to help decode the Blocked Process Report after you collect it&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Michael J. Swart&amp;rsquo;s &lt;a href="https://sqlblockedprocesses.codeplex.com/"&gt;Blocked Process Report Viewer on Codeplex&lt;/a&gt; - this makes it easy to see the lead blocker and the shape of the blocking chain. Note: you don&amp;rsquo;t have to run this on the production server itself, you can copy the files to your desktop or a test server.&lt;/li&gt;
&lt;li&gt;Once you&amp;rsquo;re looking at individual reports, my post &amp;ldquo;&lt;a href="https://kendralittle.com/2016/10/17/decoding-key-and-page-waitresource-for-deadlocks-and-blocking/"&gt;Decoding Key and Page WaitResource for Deadlocks and Blocking&lt;/a&gt;&amp;rdquo; will help you dig into the nitty gritty details&lt;/li&gt;
&lt;/ul&gt;
&lt;script src="https://gist.github.com/LitKnd/f93c10a00d01d0f4ba00b84d9ac72e1b.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/f93c10a00d01d0f4ba00b84d9ac72e1b"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;</description></item><item><title>Actual Time Statistics in Execution Plans: Elapsed CPU Time and more</title><link>https://kendralittle.com/2016/12/20/actual-time-statistics-in-execution-plans-elapsed-cpu-time-and-more/</link><pubDate>Tue, 20 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/20/actual-time-statistics-in-execution-plans-elapsed-cpu-time-and-more/</guid><description>&lt;p&gt;One of the coolest things to come to SQL Server Management Studio in a long time might be hard to see at first: it&amp;rsquo;s tucked away in the Properties Window.&lt;/p&gt;
&lt;p&gt;But once you see it, it might just be something that you use &lt;em&gt;all the time&lt;/em&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/execution-plan-music-video-set-300x300.png"
alt="execution-plan-music-video-set" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="sql-server-now-shows-actual-elapsed-cpu-time-and-actual-elapsed-time-duration-for-each-operator-in-an-actual-execution-plan"&gt;SQL Server now shows Actual Elapsed CPU Time and Actual Elapsed Time (duration) for each operator in an Actual Execution Plan&lt;/h2&gt;
&lt;p&gt;For SQL Server 2016 and 2014 SP2 and higher, actual execution plans contain a bunch of new information on each operator, including how much CPU they burn, how long it takes, and how much IO is done by that operator. This was a little hard to use for a while because the information was only visible in the XML of the execution plan.&lt;/p&gt;
&lt;p&gt;Now you can see this information with just a few clicks in the properties window of a plan. &lt;a href="https://blogs.msdn.microsoft.com/sql_server_team/extended-per-operator-level-performance-stats-for-query-processing/"&gt;Here&amp;rsquo;s the announcement from the SSMS team&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="watch-an-examplefinding-actual-time-statistics-in-an-execution-plan"&gt;Watch an example: Finding Actual Time Statistics in an Execution Plan&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an animated gif of running a query with &amp;lsquo;Actual Execution Plans&amp;rsquo; turned on, then right-clicking to see the Properties window and looking at Elapsed CPU Time (ms) and Elapsed Time (ms) for specific operators:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/VYWgrTTqR91933pz3f/source.gif"
alt="actual-elapsed-time-demo"&gt;
&lt;/figure&gt;
&lt;p&gt;Some things to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The query took just over 8 seconds to execute. (It&amp;rsquo;s shorter in the .gif because I sped up the video)&lt;/li&gt;
&lt;li&gt;The total CPU time on the index scan shows as 20+ seconds. That&amp;rsquo;s because it&amp;rsquo;s adding up the CPU time for all the threads&amp;ndash; this query is running at MAXDOP 4. The threads were pretty evenly distributed on the index scan and the longest one took about 5.2 seconds&lt;/li&gt;
&lt;li&gt;Notice how Thread 0 doesn&amp;rsquo;t accrue time? It&amp;rsquo;s the &amp;ldquo;watcher thread&amp;rdquo; that just waits for the worker threads to complete. It&amp;rsquo;s supposed to be lazy like that.&lt;/li&gt;
&lt;li&gt;The threads on the Stream Aggregate operator took some time as well&amp;ndash;  8.4 seconds on the longest thread&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wait-kendra-those-dont-add-up"&gt;Wait, Kendra, those don&amp;rsquo;t add up!&lt;/h2&gt;
&lt;p&gt;No, they don&amp;rsquo;t. That&amp;rsquo;s OK! As data flows through this execution plan, multiple operators can be busy at the same time. SQL Server doesn&amp;rsquo;t have to wait for the index scan to finish before it works on the Compute Scalar and the Stream Aggregate operator - in this case, these operators are non-blocking. (Craig Freedman writes about &lt;a href="https://blogs.msdn.microsoft.com/craigfr/2006/06/19/properties-of-iterators/"&gt;blocking vs. non-blocking operators in this post&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="lets-watch-the-same-query-with-live-query-statistics-turned-on"&gt;Let&amp;rsquo;s watch the same query with Live Query Statistics turned on&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the same query running with Live Query Stats. You can see that the data is flowing through and that multiple operators are working at the same time.&lt;/p&gt;
&lt;p&gt;We get a lot of cool information from this view, but we don&amp;rsquo;t get the same detail that we get for Actual Elapsed CPU Time and Actual Elapsed Time in the properties window of an actual execution plan. These two tools complement each other nicely.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/8l2wfzUovE9LFMNrNL/source.gif"
alt="live-query-execution-demo"&gt;
&lt;/figure&gt;
&lt;h2 id="you-can-also-see-actual-io-statistics"&gt;You can also see Actual IO Statistics&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not just about the CPUs, for each operator you can also see how many logical reads, read ahead reads, and physical reads done by that operator. And it&amp;rsquo;s all right there in the properties window now. Enjoy!&lt;/p&gt;</description></item><item><title>Limiting Downtime for Schema Changes (Dear SQL DBA Episode 25)</title><link>https://kendralittle.com/2016/12/15/limiting-downtime-for-schema-changes-dear-sql-dba-episode-25/</link><pubDate>Thu, 15 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/15/limiting-downtime-for-schema-changes-dear-sql-dba-episode-25/</guid><description>&lt;p&gt;You need to release schema changes while the SQL Server is in use. Learn why code generation tools write odd scripts and how to stay sane amid rapid releases in this 28 minute video&amp;hellip; or scroll down to read a summary.&lt;/p&gt;
&lt;p&gt;If you enjoy the podcast, please write a &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;review on iTunes&lt;/a&gt;!&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/_dYqdxUDNoQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="dear-sql-dba"&gt;Dear SQL DBA&amp;hellip;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;How can I achieve near zero downtime deployment with database schema changes? Can I use Peer-to-Peer Replication or some other feature to make this easier? It seems very complicated.
We use SQL Server Data Tools (SSDT) and the developers work agile and quite often make small changes to the schema. And we have found there are some snags with it, since SSDT generates the change script.
Here is an example of a common problem: when the developers add a column to a table you often get a Create/Insert/Drop Table create script by SSDT. Avoiding table locking when possible would help achieve near zero downtime deployment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="peer-to-peer-replication-makes-schema-changes-harder-to-manage-not-easier"&gt;Peer to Peer Replication makes schema changes harder to manage, not easier&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/not-sure-if-uptime-or-downtime-300x300.png"
alt="not-sure-if-uptime-or-downtime" width="230"&gt;
&lt;/figure&gt;
I totally get why it seemed like P2P might help with this: it&amp;rsquo;s the only technology in SQL Server where you can have multiple &amp;ldquo;write&amp;rdquo; nodes for the same database.&lt;/p&gt;
&lt;p&gt;Microsoft&amp;rsquo;s &lt;a href="https://msdn.microsoft.com/en-us/library/ms151196.aspx"&gt;documentation on Peer to Peer replication&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Publications must allow schema changes to be replicated. (This is a setting of &lt;strong&gt;1&lt;/strong&gt; for the publication property &lt;strong&gt;replicate_ddl&lt;/strong&gt;, which is the default setting.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;m not sure if that&amp;rsquo;s a hard requirement (and it just won&amp;rsquo;t work if you disable replicating schema changes), or if your use of P2P is unsupported if you disable replicating schema changes&amp;mdash; but you want to meet the requirement either way.&lt;/p&gt;
&lt;p&gt;The requirement simply makes sense when it comes to data consistency. If I drop a column in a table on Node 1 at 2 pm, should the application be allowed to insert rows into the same table on Node 2 at 2:05 pm if I haven&amp;rsquo;t applied the schema change to Node 2? How would that those rows get replicated back to Node 1?  This would put the column into a Shroedinger&amp;rsquo;s cat situation: does the column exist, or not?&lt;/p&gt;
&lt;p&gt;Other things to think about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sometimes code changes may break because they aren&amp;rsquo;t allowed by replication (such as changing a Primary Key)&lt;/li&gt;
&lt;li&gt;When you have new tables, they have to be either manually added, or you need to manage the TSQL to add them (articles aren&amp;rsquo;t added automatically)&lt;/li&gt;
&lt;li&gt;Adding or dropping articles requires quiescing, which is basically downtime for writes&lt;/li&gt;
&lt;li&gt;Changes of a very large volume of data can make the replication get behind and the system harder to manage&lt;/li&gt;
&lt;li&gt;You need to make sure that writes have been fully propagated to all nodes before moving the application to read from another node, otherwise writes they may have seen already could disappear&lt;/li&gt;
&lt;li&gt;You have to manage conflicts if the same row is modified on more than one node&lt;/li&gt;
&lt;li&gt;Peer to Peer replication is also not compatible with lots of new features at this time too (In-Memory tables, Availability Groups), which makes its future seem uncertain&lt;/li&gt;
&lt;li&gt;Peer to Peer replication is Enterprise Edition only, so if you don&amp;rsquo;t already have the licensing for multiple nodes, it&amp;rsquo;s a very expensive gamble.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Peer to Peer replication wasn&amp;rsquo;t built to solve this particular problem. You can manage schema changes while using Peer to Peer, but it&amp;rsquo;s tough stuff.&lt;/p&gt;
&lt;h2 id="enterprise-edition-has-a-cool-feature-when-it-comes-to-adding-columns"&gt;Enterprise Edition has a cool feature when it comes to adding columns&lt;/h2&gt;
&lt;p&gt;For the example you mention of adding a column, some automatic code-writing tools do the &amp;ldquo;create a new table, insert, rename&amp;rdquo; operation because adding a column in place can sometimes be a very large, painful alter because it&amp;rsquo;s a &amp;ldquo;size of data operation.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;When you add a not-nullable column with a default value, SQL Server &lt;em&gt;may&lt;/em&gt; have to go through and update every single row on the table to add that default value. That&amp;rsquo;s a really big in-place operation, and if you cancel it midway, you may be in for a nasty rollback on a large table. That&amp;rsquo;s why some folks gamble on just loading up a new table and switching it in, instead. In some cases, it&amp;rsquo;s faster!&lt;/p&gt;
&lt;p&gt;I say adding a column &lt;em&gt;may&lt;/em&gt; be a size of data operation because you have options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SQL Server Enterprise Edition has a feature where adding a new column with a default value avoids locking the table with a size of data operation.  That feature was added in SQL Server 2012. Remus Rusanu wrote a great article about it, &lt;a href="http://rusanu.com/2011/07/13/online-non-null-with-values-column-add-in-sql-server-11/"&gt;Online non-NULL with values column add in SQL Server 2012&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This doesn&amp;rsquo;t work for all data types, and it only works for a constant (not something like NEWID where every row has a different value). Read Remus&amp;rsquo; post for more details.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You also have the choice of adding your new column as nullable, and writing code to manually work through the table and populate the rows in batches.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="super-awkward---you-might-have-that-enterprise-feature-everywhere-except-production"&gt;Super awkward - you might have that Enterprise feature everywhere &lt;em&gt;except&lt;/em&gt; production&lt;/h3&gt;
&lt;p&gt;If you have Developer Edition in your development and staging environments, but Standard Edition in production, changes adding non-null columns with default values could run very quickly everywhere except production on your large tables. That&amp;rsquo;s because Developer Edition gets all the features of Enterprise Edition.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: I also talked about size of data operations in a previous Dear SQL DBA episode when I discussed another schema change: &lt;a href="https://kendralittle.com/2016/08/04/altering-an-int-column-to-a-bigint-dear-sql-dba-episode-11/"&gt;altering an INT column to a BIGINT&lt;/a&gt;.
&lt;/div&gt;
&lt;h2 id="avoiding-downtime-with-schema-changes-is-mostly-about-process-and-experience"&gt;Avoiding downtime with schema changes is mostly about process and experience&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/whoops-300x300.png"
alt="whoops" width="230"&gt;
&lt;/figure&gt;
I&amp;rsquo;ve worked in a bunch of environments where we rolled schema changes to production throughout the week, and worked hard to limit downtime. Our biggest challenges were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The code released wouldn&amp;rsquo;t have the intended effect, and multiple hotfixes would sometimes need to be written quickly if the issue was urgent.&lt;/li&gt;
&lt;li&gt;Problems would happen with replication in production - either replication would be delayed because a lot of modifications were occurring, or a change in an &amp;ldquo;upstream&amp;rdquo; system would cause a huge amount of data processing to happen in a &amp;ldquo;downstream&amp;rdquo; database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But while there were bumps along the road, we got pretty good at it! It&amp;rsquo;s not easy, but the more you do it, the better you get at it.&lt;/p&gt;
&lt;h3 id="push-schema-changes-before-application-changes"&gt;Push schema changes before application changes&lt;/h3&gt;
&lt;p&gt;Adding a new feature? Tables and columns get added to the database well in advance of anything using them. This makes it easier if the schema changes need to be rolled back. Or if something goes wrong and the schema change doesn&amp;rsquo;t succeed, that whole release doesn&amp;rsquo;t have to be rolled back.&lt;/p&gt;
&lt;h3 id="test-in-a-full-scale-pre-production-environment"&gt;Test in a full scale pre-production environment&lt;/h3&gt;
&lt;p&gt;You need a staging environment to roll changes to before they hit production. Key points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need a full dataset. If production is a 2TB database, you need a 2TB database here.&lt;/li&gt;
&lt;li&gt;This can&amp;rsquo;t be a dev environment. Dev environments are chaos, and have a bunch of pre-release code in them. This needs to match production.&lt;/li&gt;
&lt;li&gt;The environment needs to be configured like production as well&amp;ndash; if production is a cluster with replication, this environment needs to have a cluster with replication as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As long as you use this environment for testing and validating production changes, you can license this with Developer Edition &amp;ndash; but note that &amp;ldquo;super awkard&amp;rdquo; limitation above where adding a column could be fast everywhere except production. And you still need to invest in storage and hardware. (It&amp;rsquo;s possible to go cheap on the hardware, but if you do so then you won&amp;rsquo;t get a reliable estimate of how long it&amp;rsquo;s going to take to deploy changes to production.)&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re just starting down the &amp;ldquo;deploy all the time and minimize downtime&amp;rdquo; road and you don&amp;rsquo;t have this, that&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;When people start asking, &amp;ldquo;How can we make sure these mistakes don&amp;rsquo;t happen next time?&amp;rdquo;, this is your #1 suggestion.&lt;/p&gt;
&lt;h3 id="some-code-needs-to-be-custom"&gt;Some code needs to be custom&lt;/h3&gt;
&lt;p&gt;For smaller changes, it may be OK to use automatically generated code to roll the change&amp;ndash; but larger tables and sensitive databases can require custom coding to make sure you can do things like take advantage of that feature above, or custom code it.&lt;/p&gt;
&lt;p&gt;The DBA usually finds out when there&amp;rsquo;s a need for custom code when they&amp;rsquo;re pushing a change to the pre-production (aka staging) environment, and it takes longer than expected.&lt;/p&gt;
&lt;h3 id="it-needs-to-be-ok-to-screw-up-and-have-downtime"&gt;It needs to be OK to screw up and have downtime&lt;/h3&gt;
&lt;p&gt;This was totally counter-intuitive to me. The &lt;em&gt;whole point&lt;/em&gt; is that you&amp;rsquo;re trying to limit downtime.&lt;/p&gt;
&lt;p&gt;But this is hard stuff. Things are going to break. Everyone needs to be able to learn when that happens, and being afraid doesn&amp;rsquo;t help people communicate better.&lt;/p&gt;
&lt;p&gt;You need to do postmortems when you have downtime, and you need to have postmortems that &lt;em&gt;don&amp;rsquo;t suck&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;The hardest part of making this work is preventing the human tendency to blame from ruining the whole thing.&lt;/p&gt;
&lt;h2 id="but-we-really-cant-have-downtime-because-of-x-y-z"&gt;But we really can&amp;rsquo;t have downtime because of X, Y, Z&lt;/h2&gt;
&lt;p&gt;If it&amp;rsquo;s &lt;em&gt;really&lt;/em&gt; not OK for schema changes to cause downtime, because people will be harmed, too much money will be lost, or some other reason, then either:&lt;/p&gt;
&lt;p&gt;1. Releasing schema changes to SQL Server while production is active isn&amp;rsquo;t right for that application.&lt;/p&gt;
&lt;p&gt;2. You need a highly customized architecture for each application designed to make this work and avoid downtime.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For some applications, you may be able cache the reads in the application tier, or a read only copy of the database, and queue the writes while you&amp;rsquo;re doing the schema changes.&lt;/li&gt;
&lt;li&gt;Some applications may be able to be sharded into smaller databases, so data sizes are kept small. Schema changes on small tables are much simpler than large tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There may be other options as well, but it&amp;rsquo;s going to be a custom solution for each application.&lt;/p&gt;</description></item><item><title>Index Create and Last Modified Dates in SQL Server</title><link>https://kendralittle.com/2016/12/13/index-create-and-last-modified-dates-in-sql-server/</link><pubDate>Tue, 13 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/13/index-create-and-last-modified-dates-in-sql-server/</guid><description>&lt;p&gt;In many environments, it&amp;rsquo;s useful to know exactly when an index was created or modified.&lt;/p&gt;
&lt;p&gt;Did that last code release help performance, or hurt it? It&amp;rsquo;s really helpful to know exactly when the code was deployed to prove that your change made something better. Or that you might need to roll it back.&lt;/p&gt;
&lt;p&gt;It takes a little preparation to track changes to your indexes, but it&amp;rsquo;s easy to implement.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/60-year-old-index-300x300.png"
alt="60-year-old-index" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="sql-server-doesnt-really-track-index-create-or-modification-date-by-default"&gt;SQL Server doesn&amp;rsquo;t really track index create or modification date by default&lt;/h2&gt;
&lt;p&gt;I say &amp;ldquo;really&amp;rdquo;, because SQL Server&amp;rsquo;s default trace captures things like index create and alter commands. However, the default trace rolls over pretty quickly on most active servers, and it&amp;rsquo;s rare that you&amp;rsquo;re looking up the creation date for an index you created five minutes ago.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s fine that SQL Server doesn&amp;rsquo;t permanently store the creation date and modification date for most indexes, because not everyone &lt;em&gt;wants&lt;/em&gt; this information &amp;ndash; so why not make the default as lightweight as possible?&lt;/p&gt;
&lt;h3 id="you-can-get-create-date-and-last-modified-date-for-the-table--but-thats-usually-not-enough"&gt;You can get create date and last modified date for the table &amp;ndash; but that&amp;rsquo;s usually not enough&lt;/h3&gt;
&lt;p&gt;SQL Server stores when tables were created and modified in the sys.objects DMV. But most of us create and drop indexes long after the table creation time. And lots of things count as a modification in this context, including adding columns, or just rebuilding an index.&lt;/p&gt;
&lt;h3 id="if-the-index-is-a-primary-key-or-unique-index--unique-constraint-you-can-get-the-create-date"&gt;If the index is a Primary Key or Unique Index / Unique Constraint, you can get the create date&lt;/h3&gt;
&lt;p&gt;For a few indexes, you can find the creation date with a simple query &amp;ndash; because these indexes get their own row in sys.objects. You can use a query like this to find when they were created:&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/6f81465d0c539d44dfd489d0dbb8fe32#file-create-date-for-indexes-that-are-constraints.sql.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/6f81465d0c539d44dfd489d0dbb8fe32#file-create-date-for-indexes-that-are-constraints.sql"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;
&lt;p&gt;But if you&amp;rsquo;re not looking for the create date of a Primary Key, unique index, or unique constraint, you&amp;rsquo;re out of luck.&lt;/p&gt;
&lt;h2 id="track-index-creation-and-modifications-with-a-ddl-trigger"&gt;Track index creation and modifications with a DDL Trigger&lt;/h2&gt;
&lt;p&gt;DDL triggers are the simplest way to keep track of when indexes are created and dropped. This is a very easy way to record the exact time indexes are created and modified.&lt;/p&gt;
&lt;p&gt;There are a few things to know about DDL triggers, though.&lt;/p&gt;
&lt;h3 id="ddl-triggers-are-tightly-coupled-with-the-executing-code"&gt;DDL Triggers are tightly coupled with the executing code&lt;/h3&gt;
&lt;p&gt;Mostly, the folks who have a bad time with DDL triggers are DBAs who implement them in production without testing them extensively, and without talking to their developers. They create a trigger that works fine for themselves in a simple test, but may fail for someone else&amp;ndash; commonly because of a security issue.&lt;/p&gt;
&lt;p&gt;The bad news is that when the DDL trigger fails, it takes down the calling command as well. Not everyone is so happy when their table or index create suddenly fails in production with a weird error message.&lt;/p&gt;
&lt;p&gt;To make sure you have a good time with DDL Triggers to track index changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Put them in every environment, including development / text&lt;/li&gt;
&lt;li&gt;Treat them like any index related code change - check it into source code&lt;/li&gt;
&lt;li&gt;Use change control&lt;/li&gt;
&lt;li&gt;Talk to your coworkers &amp;ndash; and maybe mention that logging the exact time when DDL occurs is useful for troubleshooting and showing positive improvements, instead of making it all about policing&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="sample-ddl-trigger-code"&gt;Sample DDL trigger code&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s some simple, database level code. Make sure to check out the links at the end of this article for more samples elsewhere, too!&lt;/p&gt;
&lt;p&gt;This sample works just for one database. (Scroll to the bottom of the post for more samples on other blogs!)&lt;/p&gt;
&lt;p&gt;This code sample&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creates a schema and a table to track create and alter for tables and indexes. I did this because dropping a table is going to drop all the indexes as well.&lt;/li&gt;
&lt;li&gt;Uses row compression by default on the table. Maybe you don&amp;rsquo;t want the CPU hit on row compression, or it doesn&amp;rsquo;t work on your version/edition of SQL Server, though &amp;ndash; feel free to change it.&lt;/li&gt;
&lt;li&gt;Stores target_object_name - if you&amp;rsquo;re creating or modifying an index, this is the object name. If you&amp;rsquo;re creating or modifying a table, this is null.&lt;/li&gt;
&lt;li&gt;Stores object_name - if you&amp;rsquo;re creating or modifying an index, this is the index name&lt;/li&gt;
&lt;li&gt;Stores new_object_name - this gets populated if you use sp_rename on a table or index&lt;/li&gt;
&lt;li&gt;Has the DDL Trigger execute as dbo, and uses ORIGINAL_LOGIN() to get the login of the caller. This is to reduce risk of the DDL trigger making a schema change fail because it&amp;rsquo;s being run by an account that doesn&amp;rsquo;t have permission to write to the table you&amp;rsquo;re using for logging.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a gist of the sample code:&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/6f81465d0c539d44dfd489d0dbb8fe32#file-!ddl-trigger-sample.sql.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/6f81465d0c539d44dfd489d0dbb8fe32#file-!ddl-trigger-sample.sql"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;
&lt;h2 id="want-to-see-the-ddl-trigger-fail"&gt;Want to see the DDL Trigger fail?&lt;/h2&gt;
&lt;p&gt;Just run this code after creating the table, then the trigger:&lt;/p&gt;
&lt;script src="https://gist.github.com/LitKnd/6f81465d0c539d44dfd489d0dbb8fe32#file-test-breaking-ddl-trigger.sql.js"&gt;&lt;/script&gt;
&lt;noscript&gt;View the code on &lt;a href="https://gist.github.com/LitKnd/6f81465d0c539d44dfd489d0dbb8fe32#file-test-breaking-ddl-trigger.sql"&gt;GitHub Gist&lt;/a&gt;.&lt;/noscript&gt;
&lt;p&gt;You can&amp;rsquo;t get around that error by putting a try/catch in the DDL trigger. You going to have to ditch the DDL trigger to drop that table.&lt;/p&gt;
&lt;h2 id="an-alternative-event-notifications"&gt;An alternative: Event Notifications&lt;/h2&gt;
&lt;p&gt;If you don&amp;rsquo;t like the &amp;ldquo;tight coupling&amp;rdquo; of a DDL trigger, you can use Event Notifications to record the exact same events.&lt;/p&gt;
&lt;p&gt;The downside is that Event Notifications are a bit more complex to set up and manage. Event Notifications use Service Broker, so you need to become comfortable with the different parts of Service Broker, and managing having it on. It&amp;rsquo;s not bad, it&amp;rsquo;s just a bit more learning to do, and it&amp;rsquo;s another feature in use that you need to keep an eye out for when it comes to patching and management.&lt;/p&gt;
&lt;p&gt;If you go the Event Notifications route, I highly recommend that you configure the Event Notifications in their &lt;em&gt;own&lt;/em&gt; database, and record all the index changes there. That way, if you&amp;rsquo;re troubleshooting something and you want to turn off the logging temporarily, you can disable Service Broker just on that database where you&amp;rsquo;re doing the Event Notifications. (Enabling Service Broker requires an exclusive database lock.)&lt;/p&gt;
&lt;h2 id="more-code-samples"&gt;More code samples&lt;/h2&gt;
&lt;p&gt;Aaron Bertrand wrote a similar post on &lt;a href="https://sqlblog.org/2011/01/31/capturing-index-operations-using-a-ddl-trigger"&gt;capturing index operations in this great article&lt;/a&gt;. His sample DDL trigger is for all user databases and for create and alter events only, because he was looking for any index rebuild operations per the question.&lt;/p&gt;
&lt;p&gt;Aaron wrote another post on using DDL triggers &lt;a href="https://www.mssqltips.com/sqlservertip/2085/sql-server-ddl-triggers-to-track-all-database-changes/"&gt;to capture even more types of changes here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Does Truncate Table Reset Statistics?</title><link>https://kendralittle.com/2016/12/08/does-truncate-table-reset-statistics/</link><pubDate>Thu, 08 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/08/does-truncate-table-reset-statistics/</guid><description>&lt;p&gt;Short answer: the SQL Server optimizer will know that the table was truncated, but statistics might not update when you expect.&lt;/p&gt;
&lt;p&gt;For the long answer, let&amp;rsquo;s walk through an example using &lt;a href="https://github.com/Microsoft/sql-server-samples/tree/master/samples/databases/wide-world-importers"&gt;the WideWorldImporters sample database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be using Trace Flag 3604 and 2363 to get SQL Server to print information about how it optimized my query out to the messages tab. (&lt;a href="http://sqlblog.com/blogs/paul_white/archive/2011/09/21/how-to-find-the-statistics-used-to-compile-an-execution-plan.aspx"&gt;Thanks to Paul White for blogging about this trace flag&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="first-a-fresh-restore-of-wideworldimporters"&gt;First, a fresh restore of WideWorldImporters&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WideWorldImporters&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OFFLINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IMMEDIATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RESTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;S:MSSQLBackupWideWorldImporters-Full.bak&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="before-we-do-anything-what-do-the-statistics-look-like-on-salesorderlines"&gt;Before we do anything, what do the statistics look like on Sales.OrderLines?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the query that I&amp;rsquo;m using to inspect the statistics:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STUFF&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TYPE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NVARCHAR(MAX)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat_cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modification_counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows_sampled&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_stats_properties&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Sales&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OrderLines&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Statistics were last updated on June 2, 2016. We&amp;rsquo;ll be mostly looking at the statistic on Quantity throughout the example, so I&amp;rsquo;ve highlighted it:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Statistics-Before-Changes-1.jpg"
alt="statistics-before-changes"&gt;
&lt;/figure&gt;
&lt;h3 id="lets-run-a-query-that-loads-the-statistic-on-quantity"&gt;Let&amp;rsquo;s run a query that loads the statistic on Quantity&lt;/h3&gt;
&lt;p&gt;Before we truncate the table, let&amp;rsquo;s take a peek into how SQL Server optimizes a query that cares about rows in Sales.OrderLines with Quantity &amp;gt; 10. I&amp;rsquo;m using trace flags 3604 and 2363 to make SQL Server print information about how it used statistics to optimize this to my messages tab.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2363&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the info on the messages tab:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Begin selectivity computation
Input tree:
LogOp_Select
CStCollBaseTable(ID=1, CARD=231412 TBL: Sales.OrderLines)
ScaOp_Comp x_cmpGt
ScaOp_Identifier QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=10)
Plan for computation:
CSelCalcColumnInInterval
Column: QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity
Loaded histogram for column QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity from stats with id 7
Selectivity: 0.44231
Stats collection generated:
CStCollFilter(ID=2, CARD=102356)
CStCollBaseTable(ID=1, CARD=231412 TBL: Sales.OrderLines)
End selectivity computation
Estimating distinct count in utility function
Input stats collection:
CStCollFilter(ID=2, CARD=102356)
CStCollBaseTable(ID=1, CARD=231412 TBL: Sales.OrderLines)
Columns to distinct on:QCOL: [WideWorldImporters].[Sales].[OrderLines].OrderLineID
Plan for computation:
CDVCPlanUniqueKey
Result of computation: 102356
(102035 row(s) affected)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="highlights-one-of-the-first-thing-sql-thinks-about-is-the-number-of-rows-in-the-table"&gt;Highlights: one of the first thing SQL thinks about is the number of rows in the table&lt;/h3&gt;
&lt;p&gt;Right at the beginning, we see: &amp;ldquo;CStCollBaseTable(ID=1, CARD=231412 TBL: Sales.OrderLines)&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That &amp;lsquo;CARD&amp;rsquo; number is the optimizer thinking about how many rows are in this table. If you glance back up at the table statistics, the most recent statistic to be updated was on the &amp;lsquo;LastEditedWhen&amp;rsquo; column. When that statistic was updated, there were 231,412 rows in the table.&lt;/p&gt;
&lt;p&gt;SQL Server decides that it wants detail on the Quantity column to figure out how to run this query, so we see that it loads that statistic up to use: &amp;ldquo;Loaded histogram for column QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity from stats with id 7&amp;rdquo;&lt;/p&gt;
&lt;h2 id="lets-truncate-this-table"&gt;Let&amp;rsquo;s truncate this table&lt;/h2&gt;
&lt;p&gt;I wipe out all the rows with this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;TRUNCATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, I wouldn&amp;rsquo;t expect truncating the table to automatically update the statistics.&lt;/p&gt;
&lt;p&gt;SQL Server updates statistics when they&amp;rsquo;re used to optimize a query &amp;ndash; so if nobody queries this table for six months, I wouldn&amp;rsquo;t expect the stats to update for six months.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s re-run our query, trace flags and all:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2363&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The messages tab has less info this time- it&amp;rsquo;s much more concise!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Begin selectivity computation
Input tree:
LogOp_Select
CStCollBaseTable(ID=1, CARD=1 TBL: Sales.OrderLines)
ScaOp_Comp x_cmpGt
ScaOp_Identifier QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=10)
Plan for computation:
CSelCalcFixedFilter (0.3)
Selectivity: 0.3
Stats collection generated:
CStCollFilter(ID=2, CARD=1)
CStCollBaseTable(ID=1, CARD=1 TBL: Sales.OrderLines)
End selectivity computation
(0 row(s) affected)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="sql-server-knows-that-we-blew-away-all-those-rows"&gt;SQL Server knows that we blew away all those rows&lt;/h3&gt;
&lt;p&gt;This time we see &amp;ldquo;CARD=1 TBL: Sales.OrderLines&amp;rdquo;&lt;/p&gt;
&lt;p&gt;SQL Server doesn&amp;rsquo;t like to estimate 0 for empty tables. It likes to estimate 1. It knows this table is empty.&lt;/p&gt;
&lt;p&gt;With this information, it chooses a different plan for computation. The plan doesn&amp;rsquo;t require looking at the quantity column this time&amp;ndash; we don&amp;rsquo;t have any lines about that at all.&lt;/p&gt;
&lt;h3 id="but-the-statistics-dont-look-any-different"&gt;But the statistics don&amp;rsquo;t look any different&lt;/h3&gt;
&lt;p&gt;You might expect to see that the statistic on Quantity had updated. I expected it, before I ran through this demo.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;But SQL Server never actually had to load up the statistic on Quantity for the query above.&lt;/em&gt; So it didn&amp;rsquo;t bother to update the statistic. It didn&amp;rsquo;t need to, because it knows that the table is empty, and this doesn&amp;rsquo;t show up in our column or index specific statistics.&lt;/p&gt;
&lt;p&gt;To verify, I just rerun my metadata query above, and things look the same:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Statistics-After-Truncate-And-Query.jpg"
alt="statistics-after-truncate-and-query"&gt;
&lt;/figure&gt;
&lt;h2 id="what-if-the-table-has-exactly-one-row"&gt;What if the table has exactly one row?&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s insert one and find out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderLineID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OrderID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StockItemID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PackageTypeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UnitPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TaxRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PickedQuantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PickingCompletedWhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditedBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;164&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;32 mm Double sided bubble wrap 50m&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;112&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2013-01-02 11:00:00.0000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2013-01-02 11:00:00.0000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we run our familiar query, with all its merry trace flags:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OPTION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QUERYTRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2363&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s what SQL Server has to say about optimizing that&amp;hellip;&lt;/p&gt;
&lt;p&gt;Begin selectivity computation&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Begin selectivity computation
Input tree:
LogOp_Select
CStCollBaseTable(ID=1, CARD=1 TBL: Sales.OrderLines)
ScaOp_Comp x_cmpGt
ScaOp_Identifier QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=10)
Plan for computation:
CSelCalcColumnInInterval
Column: QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity
Loaded histogram for column QCOL: [WideWorldImporters].[Sales].[OrderLines].Quantity from stats with id 7
Selectivity: 1
Stats collection generated:
CStCollFilter(ID=2, CARD=1)
CStCollBaseTable(ID=1, CARD=1 TBL: Sales.OrderLines)
End selectivity computation
(1 row(s) affected)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="one-row-is-enough-to-use-our-column-statistic"&gt;One row is enough to use our column statistic&lt;/h3&gt;
&lt;p&gt;Looking at the beginning, CARD=1 for Sales.OrderLines, just like it did after we truncated the table. But SQL Server does something different this time, indicating that it now knows that the table isn&amp;rsquo;t really empty.&lt;/p&gt;
&lt;p&gt;It goes back to the CSelCalcColumnInInterval plan to optimize. And it loads up the column stat for the Quantity column.&lt;/p&gt;
&lt;p&gt;Since this statistic was loaded into memory, it should have auto-updated based on my database settings. Sure enough, it did:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Statistics-After-Truncate-And-Query-And-Insert.jpg"
alt="statistics-after-truncate-and-query-and-insert"&gt;
&lt;/figure&gt;
&lt;h2 id="sql-server-knows-when-youve-truncated-atable"&gt;SQL Server knows when you&amp;rsquo;ve truncated a table&lt;/h2&gt;
&lt;p&gt;And the fact that the table has been truncated may mean that it doesn&amp;rsquo;t need to use statistics on the table when optimizing queries. After all, it&amp;rsquo;s an empty table, so it can take shortcuts!&lt;/p&gt;
&lt;p&gt;So don&amp;rsquo;t get too confused if statistics look way out of date for a truncated table. Instead, ask yourself, &amp;ldquo;why am I querying a truncated table?&amp;rdquo; (Related disclaimer: I only tested this on SQL Server 2016.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to learn more about statistics in SQL Server? &lt;a href="https://kendralittle.com/2016/04/18/updating-statistics-in-sql-server-maintenance-answers/"&gt;Start here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>When Did SQL Server Last Update That Statistic? How Much Has Been Modified Since? And What Columns are in the Stat?</title><link>https://kendralittle.com/2016/12/06/when-did-sql-server-last-update-that-statistic-how-much-has-been-modified-since-and-what-columns-are-in-the-stat/</link><pubDate>Tue, 06 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/06/when-did-sql-server-last-update-that-statistic-how-much-has-been-modified-since-and-what-columns-are-in-the-stat/</guid><description>&lt;p&gt;Whether I&amp;rsquo;m working as a DBA, a consultant, a teacher, or just answering questions in my inbox, I always end up needing a script to inspect statistics one way or another.&lt;/p&gt;
&lt;p&gt;Here are some freshly written scripts for a classic DBA question: what&amp;rsquo;s going on in my stats?&lt;/p&gt;
&lt;h2 id="query-for-statistics-details-on-sql-server-2008-r2-and-higher"&gt;Query for statistics details on SQL Server 2008 R2 and higher&lt;/h2&gt;
&lt;p&gt;For most modern versions of SQL Server, I like to join to &lt;a href="https://msdn.microsoft.com/en-us/library/jj553546.aspx"&gt;sys.dm_db_stats_properties()&lt;/a&gt; &amp;ndash; you can get a LOT of detail in a single query! (This works with SQL Server 2008 R2 SP2+ / SQL Server 2012 SP1+ / All higher versions)&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the query, looking at a sample table in the WideWorldImporters database:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auto_created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STUFF&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TYPE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NVARCHAR(MAX)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat_cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_temporary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_recompute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modification_counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows_sampled&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CROSS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;APPLY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_stats_properties&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Warehouse&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StockItemTransactions&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistics_last_update_modification_counter-1024x178.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt; 
Can you guess why the top row has NULL values for last_updated, modification_counter, rows, and rows_sampled? (Once you have your guess, &lt;a href="http://www.nikoport.com/2014/09/13/clustered-columnstore-indexes-part-41-statistics/"&gt;the answer is here&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id="query-for-sql-server-2005-and-2008"&gt;Query for SQL Server 2005 and 2008.&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re using SQL Server 2008 or prior, you don&amp;rsquo;t  have the luxury of sys.dm_db_stats_properties().&lt;/p&gt;
&lt;p&gt;For these instances, it&amp;rsquo;s not a big deal to get the date statistics were last updated - we can call to the STATS_DATE() function. But we&amp;rsquo;re &lt;em&gt;really&lt;/em&gt; guessing when it comes to how many rows have been modified, we have to use a column called rowmodctr in sys.sysindexes which is a guess at how many rows have changed. It also was wildly inaccurate in some versions of SQL Server 2005.&lt;/p&gt;
&lt;p&gt;But a guessed estimate is better than no information, as long as you know it&amp;rsquo;s a guess!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auto_created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stats_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STUFF&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;statcols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_column_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TYPE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NVARCHAR(MAX)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat_cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_temporary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_recompute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATS_DATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Index stats */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rowmodctr&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sysindexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Column stats */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rowmodctr&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sysindexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sysind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;estimated_modification_counter&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Warehouse&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;StockItemTransactions&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s how the output looks:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/statistics_last_update_modification_counter_older_SQL_Servers-1024x200.jpg"&gt;
&lt;/figure&gt;
]&lt;/p&gt;
&lt;p&gt;See how the estimated modification counter is totally off in the top row, and for the column statistic? That&amp;rsquo;s because this table has a clustered columnstore index &amp;ndash; and ye olde rowmodctr column &lt;em&gt;totally&lt;/em&gt; doesn&amp;rsquo;t understand what&amp;rsquo;s going on with that!&lt;/p&gt;
&lt;p&gt;This script is going to be wrong about things like Columnstore indexes. But if you have Columnstore indexes, you&amp;rsquo;re on a version of SQL Server that lets you use the non-Dinosaur script above, which is more accurate.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TLDR;&lt;/h2&gt;
&lt;p&gt;Make sure you use the script for the correct version of SQL Server that you&amp;rsquo;re running. The &amp;ldquo;dinosaur&amp;rdquo; script is less accurate, but better than nothing when you need this.&lt;/p&gt;</description></item><item><title>Signs Your SQL Server is Running with Scissors (Dear SQL DBA Episode 24)</title><link>https://kendralittle.com/2016/12/01/signs-your-sql-server-is-running-with-scissors-dear-sql-dba-episode-24/</link><pubDate>Thu, 01 Dec 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/12/01/signs-your-sql-server-is-running-with-scissors-dear-sql-dba-episode-24/</guid><description>&lt;p&gt;Does your team know what it&amp;rsquo;s doing with SQL Server?&lt;/p&gt;
&lt;p&gt;Learn what a consultant looks for when assessing a team, and signs that SQL Server may be badly configured.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/sKz2QS9M6w8?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Watch the 23 minute video, or scroll down to read a summary of this episode. If you enjoy the podcast, &lt;a href="https://itunes.apple.com/us/podcast/dear-sql-dba/id1117507864"&gt;I’d appreciate your review on iTunes&lt;/a&gt;! Learn &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;how to ask your own Dear SQL DBA question and subscribe&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;When sitting down for the first time with an existing SQL Server environment, what do you look for as an indication that they know what they&amp;rsquo;re doing? This is along of the lines of Van Halen and the brown M&amp;amp;Ms (&lt;a href="http://www.npr.org/sections/therecord/2012/02/14/146880432/the-truth-about-van-halen-and-those-brown-m-ms"&gt;http://www.npr.org/sections/therecord/2012/02/14/146880432/the-truth-about-van-halen-and-those-brown-m-ms&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Perceptive in Pittsburgh&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What a fun question!&lt;/p&gt;
&lt;p&gt;I’ve checked out new SQL Servers a few different ways. Sometimes I’ve looked at the SQL Server for the first time live, while talking to the customer. And sometimes I’ve had a bunch of information about the SQL Server&amp;rsquo;s configuration and performance metrics to review before I ever talk to anyone.&lt;/p&gt;
&lt;p&gt;What I learned was not to judge a team by their SQL Server. Some configurations may look problematic, but make a lot more sense when I talk to the team and dig into problems they&amp;rsquo;re facing.&lt;/p&gt;
&lt;p&gt;For instance, there&amp;rsquo;ve been many times when a team was facing a performance issue, and at first glance their SQL Server looked stupidly underprovisioned in terms of memory. Upon digging into the problem I found that adding more memory wouldn&amp;rsquo;t solve their particular problem. One size doesn&amp;rsquo;t usually fit all.&lt;/p&gt;
&lt;p&gt;But there are definitely things that make me think a team has their act together. And there are specific configurations that make a DBA team look like they may need to have a little bit of an intervention.&lt;/p&gt;
&lt;h2 id="how-i-identify-a-capable-dba-team"&gt;How I identify a capable DBA team&lt;/h2&gt;
&lt;p&gt;There are two traits that make me think a team is capable of doing a good job managing a SQL Server, regardless of how much they know about the specifics of what SQL Server needs at the time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Taking ownership and responsibility for the configuration&lt;/li&gt;
&lt;li&gt;Being willing to discuss and challenge any element of the configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This doesn&amp;rsquo;t mean being willing to change any setting at the drop of the hat. It just means being open to learn and discuss changes, whatever they are, and evaluate the benefits, risks, and costs.&lt;/p&gt;
&lt;p&gt;If you have these two traits, you can get your SQL Server into great shape and care for it over time. It doesn&amp;rsquo;t matter if you know nothing about SQL Server, because taking ownership means you&amp;rsquo;re willing to learn.&lt;/p&gt;
&lt;p&gt;If you don’t have these traits, you’re going to struggle, regardless of what you know &amp;ndash; because what works well will change, and you won’t.&lt;/p&gt;
&lt;h2 id="a-litmus-test-is-your-team-capable"&gt;A litmus test: is your team capable?&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/some-teams-300x300.png"
alt="some-teams" width="230"&gt;
&lt;/figure&gt;
Do you ever find yourself saying or thinking something like this?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There&amp;rsquo;s no way that we can do (some change), because I can&amp;rsquo;t get the (money / permission / other resource)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have that kind of mental block, you&amp;rsquo;re &lt;em&gt;not really&lt;/em&gt; taking ownership and responsibility for the configuration.&lt;/p&gt;
&lt;p&gt;This is a matter of perspective, but it&amp;rsquo;s a perspective that makes a huge difference. We all work with funding and resource constraints. If you see a change in configuration that you think would be beneficial, the perspective of the capable team is that you want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify scenarios where the change will make an improvement&lt;/li&gt;
&lt;li&gt;Research and find resources to back up your idea&lt;/li&gt;
&lt;li&gt;Design a way to measure the current state and potentially create a testing scenario to prove that it will work&lt;/li&gt;
&lt;li&gt;Make a plan to make your case to business owners&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s possible that the change won&amp;rsquo;t be approved. That&amp;rsquo;s OK &amp;ndash; you file away your information, and if more incidents come up around the problem you&amp;rsquo;re trying to solve, you&amp;rsquo;re prepared with a possible solution.&lt;/p&gt;
&lt;p&gt;Essentially, the capable team has the perspective, &amp;ldquo;What can we do to make this better?&amp;rdquo; They ask this question even if they can&amp;rsquo;t implement all the solutions.&lt;/p&gt;
&lt;p&gt;If you and your team don&amp;rsquo;t have this perspective, this is something you can change. You don&amp;rsquo;t have to try to change others: just work to change your own perspective. If you can successfully change your approach and viewpoint, it will naturally spread to your team. (And as a big bonus, it&amp;rsquo;s likely to make you a happier employee.)&lt;/p&gt;
&lt;h2 id="five-signs-that-your-sql-server-is-running-with-scissors"&gt;Five signs that your SQL Server is running with scissors&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/sql-underpants-300x300.png"
alt="sql-underpants" width="230"&gt;
&lt;/figure&gt;
All this being said, there are some settings that make it look like you don’t know what you’re doing with a SQL Server.&lt;/p&gt;
&lt;h3 id="1-priority-boost-is-enabled"&gt;1. Priority Boost is enabled&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s been a warning on the &lt;a href="https://msdn.microsoft.com/en-us/library/ms188709.aspx"&gt;Books Online entry for Priority Boost&lt;/a&gt; for years which says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Raising the priority too high may drain resources from essential operating system and network functions, resulting in problems shutting down SQL Server or using other operating system tasks on the server.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s also deprecated. But it&amp;rsquo;s still enabled on plenty of SQL Servers.&lt;/p&gt;
&lt;p&gt;Finding this is like seeing the sky turn green. You know that you&amp;rsquo;re in for a colorful time, because &lt;em&gt;who know__s&lt;/em&gt; what else is going on.&lt;/p&gt;
&lt;h3 id="2-processor-affinity-masking-is-configured"&gt;2. Processor affinity masking is configured&lt;/h3&gt;
&lt;p&gt;This is a sign that the SQL Server isn&amp;rsquo;t properly licensed. Some folks think that they can use processor affinity to reduce SQL Server&amp;rsquo;s licensing costs: they want to limit SQL Server to use only a specific number of cores, and pay for that exact number.&lt;/p&gt;
&lt;p&gt;SQL Server licensing doesn&amp;rsquo;t work that way. You need to license all the cores that are provisioned to the Virtual Machine at the guest level, or license the physical cores installed in the server at the host level.&lt;/p&gt;
&lt;p&gt;Finding this is really not fun, because it&amp;rsquo;s a very expensive piece of bad news to deliver.&lt;/p&gt;
&lt;h3 id="3-backup-log-with-truncate_only-no_log--disk-nul"&gt;3. Backup Log with TRUNCATE_ONLY / NO_LOG / DISK =&amp;lsquo;NUL:&amp;rsquo;&lt;/h3&gt;
&lt;p&gt;This one is becoming more rare because Microsoft removed the syntax for log backups with TRUNCATE_ONLY and NO_LOG in SQL Server 2008. That seems to have helped people understand that throwing away a log backup isn&amp;rsquo;t a good idea. If you don&amp;rsquo;t need point in time recovery and incremental restores, use the SIMPLE recovery model instead.&lt;/p&gt;
&lt;p&gt;But some people still use the workaround which Microsoft left in place, where you can back up a log to NULL. This usually gets left in place if people were trying random fixes from the internet and didn&amp;rsquo;t understand what they were doing.&lt;/p&gt;
&lt;h3 id="4-auto-shrink-is-on-when-performance-is-important"&gt;4. Auto-shrink is on when performance is important&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s very well documented on the internet that shrinking can cause problems in SQL Server, and that auto-shrink is bad. It can cause blocking, random performance problems, and if you feed auto-shrink after midnight then your SQL Server will wreck the datacenter.&lt;/p&gt;
&lt;p&gt;But I still sometimes find auto-shrink enabled.&lt;/p&gt;
&lt;p&gt;The funny thing about this one is that usually people know they shouldn&amp;rsquo;t have it on, and are surprised by it. Finding this is usually a sign that the team is stuck in such a reactive fire-fighting mode that they haven&amp;rsquo;t scheduled any time to evaluate basic configuration errors.&lt;/p&gt;
&lt;h3 id="5-multiple-instances-in-the-same-windows-install-when-performance-is-important"&gt;5. Multiple instances in the same Windows install when performance is important&lt;/h3&gt;
&lt;p&gt;This is an example of finding old-school thinking that doesn&amp;rsquo;t make sense anymore. &amp;ldquo;Instance stacking&amp;rdquo; is when you install multiple SQL Server instances into the same Windows install. SQL Server lets you do it, and it&amp;rsquo;s supported to do so.&lt;/p&gt;
&lt;p&gt;But when performance is important, this is a nightmare to manage. It&amp;rsquo;s like having a house full of hungry teenagers where any one of them can eat all the food in the fridge IN AN INSTANT, and then the other teenagers get really upset if they are awake.&lt;/p&gt;
&lt;p&gt;If performance is important, the better approach is to either consolidate the instances (thereby simplifying troubleshooting by letting one SQL OS schedule resources across the whole server), or separate your teenagers into their own apartments using virtualization. If you have security reasons to keep &amp;rsquo;em separated, virtualization gives you much more flexibility over time.&lt;/p&gt;
&lt;p&gt;Finding this often means that the team used some really old information when they designed the environment, because instance-stacking was popular when Avril Lavigne first came out.&lt;/p&gt;
&lt;h2 id="what-do-i-do-to-take-control-of-my-sql-server"&gt;What do I do to take control of my SQL Server?&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/scissors-300x300.png"
alt="scissors" width="230"&gt;
&lt;/figure&gt;
I don&amp;rsquo;t mean to shame anyone who realizes they&amp;rsquo;ve got a problem in these areas, or who isn&amp;rsquo;t sure.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not a personal failing. It doesn&amp;rsquo;t mean you&amp;rsquo;re dumb. It means you have a prioritization problem. You need to make some time soon to step back and take charge of your configuration.&lt;/p&gt;
&lt;p&gt;Talk to your manager about planning some time soon for you to perform a SQL Server health check. Look at free tools available for this online, and practice using them in a test environment. Then take a look at your production server.&lt;/p&gt;
&lt;p&gt;Here are some free tools that may help you out &amp;ndash; check them out, test em, and pick your favorite:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Brent Ozar Unlimited&amp;rsquo;s sp_Blitz script from the First Responder Kit: &lt;a href="https://www.brentozar.com/blitz/"&gt;https://www.brentozar.com/blitz/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SQL Skills&amp;rsquo; Diagnostic Queries: &lt;a href="http://www.sqlskills.com/blogs/glenn/category/dmv-queries"&gt;http://www.sqlskills.com/blogs/glenn/category/dmv-queries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;rsquo;t rush in to randomly changing settings. Document everything first, and then use a good change control process. If you don&amp;rsquo;t have change control in place, &lt;a href="https://kendralittle.com/2016/04/12/change-management-template-for-sql-server-dbas-and-deveopers/"&gt;start with my free Change Control Template&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Learn to Tune Indexes in Lisbon on March 9, 2017</title><link>https://kendralittle.com/2016/11/30/learn-to-tune-indexes-in-lisbon-march-9-2017/</link><pubDate>Wed, 30 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/30/learn-to-tune-indexes-in-lisbon-march-9-2017/</guid><description>&lt;p&gt;Want to learn to tune indexes in SQL Server? I&amp;rsquo;ll be teaching a day-long pre-conference session in Portugal in March. Hope to see you there, or at &lt;a href="http://www.sqlsaturday.com/583/eventhome.aspx"&gt;SQL Saturday Lisbon (free!) the following weekend&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the details on the course and how to reserve a seat.&lt;/p&gt;
&lt;h2 id="how-to-tune-sql-server-indexes-with-execution-plans"&gt;How to Tune SQL Server Indexes with Execution Plans&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://app.weventual.com/detalheEvento.action?iDEvento=3845"&gt;Reserve your seat here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an overview of what you&amp;rsquo;ll learn in the course, or scroll on down to read the details.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/WUpaIc_i9Cg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;SQL Server asks for a lot of indexes &amp;ndash; but it doesn&amp;rsquo;t always ask for the right index! You need to know the essential principles of index design to create the best nonclustered index, filtered index, or indexed view to speed up your critical queries.&lt;/p&gt;
&lt;p&gt;In this example-packed day long session, you will work through a series of simple problems and solutions to learn how to create and tune disk-based, rowstore indexes. You will learn how to choose the right key columns, when included columns help, when to use special indexes, and how to avoid workload-killing gotchas.&lt;/p&gt;
&lt;p&gt;Throughout the day, you&amp;rsquo;ll learn to use query execution plans to decode how SQL Server is using your index, and whether or not changing the index is likely to make your query even faster. You will see how SQL Server 2016’s Query Store feature offers you new tools for improving your indexes, and how Query Store compares to index Dynamic Management Views. You&amp;rsquo;ll leave with all the scripts for the problems and solutions covered in the course.&lt;/p&gt;
&lt;p&gt;Students will learn to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interpret execution plans to understand how indexes are being used&lt;/li&gt;
&lt;li&gt;Use execution plan analysis to suggest index changes to improve query performance&lt;/li&gt;
&lt;li&gt;Measure and record query performance accurately to document index efficiency and improvement&lt;/li&gt;
&lt;li&gt;Critique and improve SQL Server&amp;rsquo;s suggestions for indexes&lt;/li&gt;
&lt;li&gt;Practice designing indexes, predicting how SQL Server will use them, and test the results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contents/Topics covered in the workshop:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nonclustered Index Key Choice&lt;/li&gt;
&lt;li&gt;Keys vs Included Columns&lt;/li&gt;
&lt;li&gt;Indexing for TOP / ORDER BY&lt;/li&gt;
&lt;li&gt;Indexing a non-SARGABLE Predicate&lt;/li&gt;
&lt;li&gt;Indexing for GROUP BY&lt;/li&gt;
&lt;li&gt;Changing a Clustered Index&lt;/li&gt;
&lt;li&gt;Strategizing Index Optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://app.weventual.com/detalheEvento.action?iDEvento=3845"&gt;Register today&lt;/a&gt;!&lt;/p&gt;</description></item><item><title>How to Tune Indexes for a Stored Procedure</title><link>https://kendralittle.com/2016/11/29/the-best-way-to-tune-indexes-for-a-stored-procedure/</link><pubDate>Tue, 29 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/29/the-best-way-to-tune-indexes-for-a-stored-procedure/</guid><description>&lt;p&gt;You&amp;rsquo;ve got an important stored procedure that you think needs index help&amp;ndash; but it runs in environment with lots of other queries. How do you focus in and discover exactly what indexes need tuning for that procedure?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/stopwatch-300x300.png"
alt="stopwatch" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="the-best-way-totune-indexes-in-a-stored-procedure"&gt;The best way to tune indexes in a stored procedure&lt;/h2&gt;
&lt;p&gt;The best way is to run the stored procedure yourself to generate and save an &amp;ldquo;actual&amp;rdquo; execution plan, which contains the estimates SQL Server used when it generated the plan as well as actual rowcounts, actual memory granted, etc. It will also contain a green tooltip with a &amp;ldquo;missing index request&amp;rdquo; if SQL Server thinks an index would help.&lt;/p&gt;
&lt;p&gt;Tips on how to tune procedures with actual execution plans:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you execute the stored procedure from a free tool like SQL Sentry Plan Explorer, you can even save off the plans (which will have green missing index requests where SQL Server thinks they would help), &lt;a href="https://kendralittle.com/2016/09/27/measuring-query-duration-ssms-vs-sql-sentry-plan-explorer/"&gt;along with runtime stats about CPU usage, reads, and duration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Runtime stats are really important and can save you tuning time. When looking at execution plans, remember that all references to &amp;ldquo;costs&amp;rdquo; are estimates. A query could have a high estimated cost, but only take 2 milliseconds of duration. Usually that&amp;rsquo;s not worth your time to tune!&lt;/li&gt;
&lt;li&gt;Most procedures are parameterized. You want to run the procedure with real world values for those parameters. You also want to test what happens when you run it with a different set of parameters and re-use the execution plan generated by the first set.&lt;/li&gt;
&lt;li&gt;Always look at those missing index requests as suggestions. You may be able to improve upon them, and they may not always show up when an index change is needed! Look for expensive operations in queries with a long duration and ask yourself if an index might help.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The biggest problem&lt;/strong&gt; is that you can&amp;rsquo;t always run a procedure against production. Sometimes the procedure modifies data, sometimes it just impacts performance too much. You can work around this by restoring a recent backup to a different environment where it&amp;rsquo;s safe to test.&lt;/p&gt;
&lt;h2 id="if-you-cant-get-actual-execution-plans-with-runtime-stats-there-are-a-couple-of-alternatives"&gt;If you can&amp;rsquo;t get actual execution plans with runtime stats, there are a couple of alternatives&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Nearly as good:&lt;/strong&gt; &lt;a href="https://msdn.microsoft.com/en-us/library/dn817826.aspx"&gt;enable SQL Server 2016&amp;rsquo;s Query Store&lt;/a&gt; feature. It will collect runtime stats (cpu usage, duration, reads, writes) and execution plans from production. They aren&amp;rsquo;t actual plans (no actual rowcounts, etc), but it&amp;rsquo;s still a lot of useful information. However, you have to be on SQL Server 2016, and Query Store is per-database &amp;ndash; so you need to enable it in every database the procedure touches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One way that sometimes works&lt;/strong&gt; is to get the cached execution plan from memory in production along with the query execution stats (cpu usage, duration, reads, writes). You can do this using a free script like &lt;a href="https://www.brentozar.com/blitzcache/"&gt;sp_BlitzCache from Brent Ozar Unlimited&lt;/a&gt;, or &lt;a href="http://www.sqlskills.com/blogs/glenn/category/dmv-queries/"&gt;Glenn Berry&amp;rsquo;s free scripts from SQL Skills&lt;/a&gt;. However, the plan isn&amp;rsquo;t always in memory when you look, and these aren&amp;rsquo;t actual plans, either.&lt;/p&gt;
&lt;h2 id="methods-iwould-avoid"&gt;Methods I would avoid&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;I wouldn&amp;rsquo;t spend much time&lt;/strong&gt; looking at the &amp;ldquo;Missing Index DMVs&amp;rdquo; for this particular problem. In theory, you can record what indexes SQL Server has asked for, let things run, and then see what requests are new. But in practice, I&amp;rsquo;ve always found this information to be too incomplete and frustrating, because it doesn&amp;rsquo;t tell you how long things took, SQL Server doesn&amp;rsquo;t always ask for an index, and the requests aren&amp;rsquo;t always perfect. I find it much easier to have the execution plans and queries for reference &amp;ndash; ideally actual plans, but at least estimated plans with runtime stats.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I would avoid running a trace&lt;/strong&gt; to collect execution plans in production. Whether with Profiler, Server Side Trace, or Extended Events, collecting execution plans unfortunately slows down your SQL Server&amp;ndash; so you&amp;rsquo;re impacting performance for the server, and also skewing your measurement. (&lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/732870/sqlserver-query-post-execution-showplan-performance-impact"&gt;Vote up this Connect bug on the issue if you like traces and wish this was better&lt;/a&gt;. The bug is closed, but sometimes closed bugs are reopened and fixed.)&lt;/p&gt;</description></item><item><title>Why is My Query Faster the Second Time it Runs? (Dear SQL DBA Episode 23)</title><link>https://kendralittle.com/2016/11/25/why-is-my-query-faster-the-second-time-it-runs-dear-sql-dba-episode-23/</link><pubDate>Fri, 25 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/25/why-is-my-query-faster-the-second-time-it-runs-dear-sql-dba-episode-23/</guid><description>&lt;p&gt;Today&amp;rsquo;s question is about why a query might be slow at first, then fast the next time you run it.&lt;/p&gt;
&lt;p&gt;Watch the 26 minute video or scroll on down and read the written version of the episode instead.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Zj-7vMOXrEY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;Whenever I create a complex view, the first time I use it in a query, the query is slow. The same thing happens after I alter the view. What is the reason behind this?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a great question &amp;ndash; because when you ask this question, you&amp;rsquo;re about to discover a lot of interesting, useful things about how SQL Server runs queries.&lt;/p&gt;
&lt;p&gt;There are two ways that SQL Server can use memory to make a query faster the second time you run it. Let&amp;rsquo;s talk about how the magic happens.&lt;/p&gt;
&lt;h2 id="it-takes-cpu-time-to-figure-out-how-to-run-a-query-sql-server-uses-memory-to-cache-execution-plans-to-save-time-the-next-time-you-run-the-query"&gt;It takes CPU time to figure out how to run a query. SQL Server uses memory to cache execution plans to save time the next time you run the query.&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Slow-then-Fast-300x300.png"
alt="slow-then-fast" width="230"&gt;
&lt;/figure&gt;
The first time you run a query using the view, SQL Server has to &amp;lsquo;compile&amp;rsquo; an execution plan to figure out the best way to run the query.&lt;/p&gt;
&lt;p&gt;SQL doesn&amp;rsquo;t compile the plan when you create the view&amp;ndash; it compiles a plan when you first use the view in a query. After all, you could use the view in a query in different ways: you might select only some columns, you could use different &amp;lsquo;where&amp;rsquo; clauses, you could use joins.&lt;/p&gt;
&lt;p&gt;Secretly, it doesn&amp;rsquo;t matter too much that you&amp;rsquo;re using a view. When you run a query that references it, behind the scenes SQL Server will expand the TSQL in the view just like any other query, and it will look for ways to simplify it.&lt;/p&gt;
&lt;p&gt;So SQL Server waits to compiles a plan for the exact query you run.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Depending on how many joins are in the view and how many ways SQL Server could run the query, it may take it a while to compile the query execution plan.&lt;/li&gt;
&lt;li&gt;SQL Server tries to come up with a decent plan quickly. But I have seen some cases where query compile time took 5+ seconds, and query execution time was much smaller.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SQL Server is designed to store the execution plan for a query in memory in the execution plan cache, in case you run it again. It would be very costly for the CPUs to generate a plan for every query, and people tend to re-run many queries.&lt;/p&gt;
&lt;p&gt;If you re-run a query and there is already an execution plain in the plan cache, SQL Server can use and save all that compile time.&lt;/p&gt;
&lt;p&gt;When you alter a view, this will force SQL Server to generate a new execution plan the first time a query uses the view afterward. Something has changed, so SQL Server can&amp;rsquo;t use any plans that were in cache before.&lt;/p&gt;
&lt;p&gt;Restarting the SQL Server, taking the database offline and online, memory pressure, and many server level settings changes will also clear execution plans out of cache, so you have to wait for a compile.&lt;/p&gt;
&lt;h3 id="how-much-time-are-you-spending-compiling"&gt;How much time are you spending compiling?&lt;/h3&gt;
&lt;p&gt;There are a few ways to see this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you are testing and want to see how much time is spent on compiling, you can run in your session: &lt;a href="https://msdn.microsoft.com/en-us/library/ms190287.aspx"&gt;SET STATISTICS TIME ON&lt;/a&gt;; After that, SQL will show you the &amp;lsquo;parse and compile time&amp;rsquo; for each query in your &amp;lsquo;Messages&amp;rsquo; window for that session.&lt;/li&gt;
&lt;li&gt;If you&amp;rsquo;re looking at execution plans, &amp;lsquo;compile time&amp;rsquo; is stored in the XML. You can see it in the properties on the upper left-most operator. It&amp;rsquo;s reported in milliseconds and is the same as the &amp;rsquo;elapsed time&amp;rsquo; that appears under parse and compile time from SET STATISTICS TIME.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Compile-Time-in-Execution-Plan.jpg"
alt="compile-time-in-execution-plan"&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;Query Store collects compilation time statistics, including compile duration. You can see some of the details in this post I wrote on &lt;a href="https://kendralittle.com/2015/11/25/option-recompile-query-store-execution-plan/"&gt;Query Store and recompile hints&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="views-arent-really-a-problem-sometimes-lots-of-joins-are-a-problem-but-sql-server-still-has-tricks-to-compile-a-plan-quickly"&gt;Views aren&amp;rsquo;t really a problem. Sometimes, lots of joins are a problem, but SQL Server still has tricks to compile a plan quickly.&lt;/h3&gt;
&lt;p&gt;When people use complex views, particularly nested views, they often end up with a LOT of joins in each query.&lt;/p&gt;
&lt;p&gt;When SQL Server has a lot of joins, optimization gets harder. There&amp;rsquo;s a ton of ways the query would be executed.&lt;/p&gt;
&lt;p&gt;The SQL Server optimizer doesn&amp;rsquo;t want you to wait a long time while it looks at every single thing it could possibly do. It takes some shortcuts. It wants to get to a good plan &lt;em&gt;fast&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Generally, SQL Server tries to keep optimization times short, even when you have a lot of joins.&lt;/p&gt;
&lt;p&gt;But there are cases where sometimes compilation takes longer than normal.&lt;/p&gt;
&lt;h3 id="what-if-you-see-multiple-seconds-of-parse-and-compile-time"&gt;What if you see multiple seconds of parse and compile time?&lt;/h3&gt;
&lt;p&gt;Usually compilation time is a number of milliseconds, but I have seen some cases where it&amp;rsquo;s seconds. This could be for a few reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SQL Server had to wait for CPU when it was trying to compile the query. It&amp;rsquo;s not the query&amp;rsquo;s fault, there just weren&amp;rsquo;t processors available. I would look at SQL Server&amp;rsquo;s wait statistics to identify this. If there were notable SOS_SCHEDULER_YIELD waits in that time period, the issue is more server load than the specific query.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ve hit an identified bug for compile time. Some cumulative updates for SQL Server fix long compilation times. It&amp;rsquo;s worth looking at the version of SQL Server you&amp;rsquo;re on, setting up a fully patched test instance, and checking if applying updates might improve your compilation times.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ve hit an unidentified bug for compile time. SQL Server works pretty hard to compile plans quickly, so multi-second compile time usually looks like a bug to me, if it&amp;rsquo;s not due to server load. For views and complex queries, I would:
&lt;ul&gt;
&lt;li&gt;Look to see if I could simplify the query where-ever possible, to make things easier for the optimizer.&lt;/li&gt;
&lt;li&gt;Check if indexes might simplify the plan. Good indexes can make choosing a good plan easier and faster.&lt;/li&gt;
&lt;li&gt;Try query hints as a last resort. The problem is that hints are really directives, and force a behavior &amp;ndash; what&amp;rsquo;s beneficial to force today may not be so great after the next upgrade, or even  if my data sizes change over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="it-takes-time-to-read-data-from-disk-sql-server-uses-memory-to-cache-data-in-the-buffer-pool-so-it-doesnt-have-to-go-to-disk-the-next-time-you-use-that-data"&gt;It takes time to read data from disk. SQL Server uses memory to cache data in the Buffer Pool so it doesn&amp;rsquo;t have to go to disk the next time you use that data.&lt;/h2&gt;
&lt;p&gt;There are more reasons that the second run of a query might be faster.&lt;/p&gt;
&lt;p&gt;The first time you run the query it may be using data that is on disk. It will bring that into memory (this memory is called the “buffer pool”). If you run the query again immediately afterward and the data is already in memory, it may be much faster &amp;ndash; it depends how much memory it had to go read from disk, and how slow your storage system is.&lt;/p&gt;
&lt;p&gt;When you are testing, you can see if your query is reading from disk (physical reads and read ahead reads) by running: &lt;a href="https://msdn.microsoft.com/en-us/library/ms184361.aspx"&gt;SET STATISTICS IO ON&lt;/a&gt;;&lt;/p&gt;
&lt;p&gt;One difference with this type of memory is that your buffer pool memory is not impacted by ALTERING the view. SQL Server does not dump data from the buffer pool when you change a view or procedure. Instead, it keeps track of how frequently different pages of data are used, and ages out the least useful pages from memory over time.&lt;/p&gt;
&lt;p&gt;So this might be part of the answer in your case, but it wouldn&amp;rsquo;t necessarily explain why the query would be slower on the first run after an ALTER &amp;ndash; unless the data pages that you&amp;rsquo;re using just hadn&amp;rsquo;t been queried a while and were no longer in the buffer pool cache by chance.&lt;/p&gt;
&lt;h2 id="takeaways-for-testing-queries"&gt;Takeaways for testing queries&lt;/h2&gt;
&lt;h3 id="i-usually-tune-queries-with-a-warm-cache"&gt;I usually tune queries with a &amp;ldquo;warm cache&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Most queries that reference commonly used tables have a good chance of the data they need being in cache.&lt;/p&gt;
&lt;p&gt;To test against a warm cache, I run the query once, and don&amp;rsquo;t pay a ton of attention to that first run.&lt;/p&gt;
&lt;p&gt;I run the query again and measure the duration with the execution plan cached and the data pages in the buffer pool.&lt;/p&gt;
&lt;h3 id="you-can-tune-with-a-cold-cache-but-be-careful"&gt;You can tune with a &amp;ldquo;cold cache&amp;rdquo;, but be careful&lt;/h3&gt;
&lt;p&gt;If I have a reason to believe that the data won&amp;rsquo;t be in cache when the query is run, then I will test it against a &amp;ldquo;cold cache&amp;rdquo;. I might need to do this if it&amp;rsquo;s a nightly query that runs, and the data it uses isn&amp;rsquo;t relevant at all to the daytime workload&amp;ndash; so the pages are likely to not be in the buffer pool when it&amp;rsquo;s time for the job to run that night.&lt;/p&gt;
&lt;p&gt;To test against a cold cache, you have to do some things that are NOT friendly for a production server &amp;ndash; so make sure you only use this approach against test instances:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;a href="https://msdn.microsoft.com/en-us/library/ms187762.aspx"&gt;DBCC DROPCLEANBUFFERS&lt;/a&gt; to flush unmodified pages from the buffer pool. (This will slow down your whole instance because EVERYBODY then has to start reading from disk)&lt;/li&gt;
&lt;li&gt;If modifications have been happing as part of the test, run a manual &lt;a href="https://msdn.microsoft.com/en-us/library/ms188748.aspx"&gt;CHECKPOINT&lt;/a&gt; to flush dirty pages to disk from the buffer pool&lt;/li&gt;
&lt;li&gt;Use RECOMPILE hints or a variant of &lt;a href="https://msdn.microsoft.com/en-us/library/ms174283.aspx"&gt;DBCC FREEPROCCACHE&lt;/a&gt; to make sure I measure compilation time each time&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Should I change the locks configuration in SQL Server?</title><link>https://kendralittle.com/2016/11/22/should-i-change-the-locks-configuration-in-sql-server/</link><pubDate>Tue, 22 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/22/should-i-change-the-locks-configuration-in-sql-server/</guid><description>&lt;p&gt;I recently got a fantastic question from a reader regarding lock usage in SQL Server:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of my production databases has a total lock count around 25,000 (select count(*) from sys.dm_tran_locks). The configuration setting for locks is set to the default of zero. This lock count is due to multiple procedures which frequently run and use the same 2-3 tables, repeatedly taking out and releasing locks. Do I need to change the configuration for locks or look into the SP&amp;rsquo;s so they can finish more quickly, rather than creating locks?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="our-friend-is-correctto-leave-thelocks-setting-in-sp_configure-alone"&gt;Our friend is correct to leave the &amp;rsquo;locks&amp;rsquo; setting in sp_configure alone&lt;/h2&gt;
&lt;p&gt;The default setting of zero lets SQL Server &lt;a href="https://msdn.microsoft.com/en-us/library/ms190253.aspx"&gt;manage the memory for locks dynamically&lt;/a&gt;. When use this dynamic setting, SQL Server will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allocate memory for 2,500 locks on startup&lt;/li&gt;
&lt;li&gt;Acquire more memory for locks when it needs to do so (unless you&amp;rsquo;re in a memory pressure situation and it would cause paging)&lt;/li&gt;
&lt;li&gt;Not allocate more than 60% of the memory allocated to the instance for locks&lt;/li&gt;
&lt;li&gt;Trigger lock escalation when lock memory hits 40% of the memory allocated to the instance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you change the setting for &amp;rsquo;locks&amp;rsquo;, you&amp;rsquo;re giving SQL Server a maximum number of locks that it can use.&lt;/p&gt;
&lt;p&gt;Microsoft recommends leaving this at zero.&lt;/p&gt;
&lt;p&gt;You could change &amp;rsquo;locks&amp;rsquo; to raise the number of locks allowed. But is it a good idea to use more than 60% of your memory for locks? Even if you&amp;rsquo;re using that as a temporary band-aid, leaving less than 40% of your memory for buffer pool (data cache), execution plans, and everything else is going to be a world of hurt for most instances..&lt;/p&gt;
&lt;p&gt;You could change &amp;rsquo;locks&amp;rsquo;  to lower the number of locks allowed. But not allocating locks means that the queries asking for locks are going to throw errors and fail. That&amp;rsquo;s not attractive, either.&lt;/p&gt;
&lt;p&gt;So if you&amp;rsquo;re concerned about the number of locks you have, changing the &amp;rsquo;locks&amp;rsquo; configuration setting isn&amp;rsquo;t likely to help you out.&lt;/p&gt;
&lt;p&gt;The &amp;rsquo;locks&amp;rsquo; configuration is also marked as slated to be removed in a future version. Microsoft doesn&amp;rsquo;t want you to be dependent on it.&lt;/p&gt;
&lt;h2 id="whats-the-memory-overhead-of-those-locks"&gt;What&amp;rsquo;s the memory overhead of those locks?&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Locks-300x300.png"
alt="locks" width="230"&gt;
&lt;/figure&gt;
Each lock uses 96 bytes of memory. On the instance in question, 25,000 locks  = 2,400,000 bytes.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s only 2.3 MB of memory devoted to locks. Even though 25K  sounds like a lot, the memory footprint for that is pretty darn small.&lt;/p&gt;
&lt;p&gt;I checked back with our questioner, and their instance has 32GB of memory. That&amp;rsquo;s a pretty small amount in the grand scheme of things (as of SQL Server 2014, Standard Edition can use up to 128GB of memory for the Buffer Pool), but 2.3 MB isn&amp;rsquo;t anything to worry about, percentage wise.&lt;/p&gt;
&lt;h2 id="do-you-have-a-high-number-of-locks-because-you-need-betterindexes"&gt;Do you have a high number of locks because you need better indexes?&lt;/h2&gt;
&lt;p&gt;Good indexes can dramatically reduce your lock overhead. Here&amp;rsquo;s a simple example using the &lt;a href="https://github.com/LitKnd/BabbyNames"&gt;SQLIndexWorkbook sample database &amp;ndash; now renamed to BabbyNames&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For this sample query, run under the default read committed isolation level:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstNameByYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstNameId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When this needs to do a clustered index scan, it requires &lt;strong&gt;5,061 page locks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After creating a nonclustered index on FirstNameId, the query requires &lt;strong&gt;only one page lock&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Indexes that help SQL Server find rows more quickly can dramatically reduce the number of locks that are taken out.&lt;/p&gt;
&lt;h2 id="are-you-waiting-for-locks-because-of-blocking"&gt;Are you waiting for locks because of blocking?&lt;/h2&gt;
&lt;p&gt;SQL Server is fast at acquiring locks &amp;ndash; unless there&amp;rsquo;s a conflict, and you have to wait to get the lock because someone else is already using it.&lt;/p&gt;
&lt;p&gt;In this case, the first step is to figure out when there is blocking, and who is blocking whom. I like to use &lt;a href="https://kendralittle.com/2016/09/29/setting-up-free-blocking-alerts-and-deadlock-monitoring-dear-sql-dba-episode-17/"&gt;alerts and the Blocked Process Report to help figure this out&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="do-you-have-a-high-number-of-locks-because-ofestimate-problems"&gt;Do you have a high number of locks because of estimate problems?&lt;/h2&gt;
&lt;p&gt;One reason you might get a high number of locks is an inefficient execution plan based on poor estimates. If SQL Server thinks it&amp;rsquo;s only going to get a small number of rows, it may design a plan based on &amp;ldquo;lookups&amp;rdquo;. If it turns out that it&amp;rsquo;s got a lot more rows than it thought, it might have to execute this loop over and over and over&amp;ndash; slowly looping and acquiring lots of little locks.&lt;/p&gt;
&lt;p&gt;In this case, the stored procedures using this database are making heavy use of table variables. Table variables often lead to incorrect estimates in complex procedures, and could result in inefficient plans.&lt;/p&gt;
&lt;p&gt;In this case, I wasn&amp;rsquo;t too worried about the 25,000 locks, but I thought it was possible that the performance of the procedures might be able to be improved if they have better estimates. I recommended:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Testing out the procedures in a dev environment with temporary tables instead of table variables&lt;/li&gt;
&lt;li&gt;Evaluating how the procedures use indexes after the change &amp;ndash; they likely will need different indexes for the new execution plans&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you have heavy use of table variables and can&amp;rsquo;t test out temporary tables, you can test out &lt;a href="https://blogs.msdn.microsoft.com/psssql/2014/08/11/having-performance-issues-with-table-variables-sql-server-2012-sp2-can-help/"&gt;Trace Flag 2453 on SQL Server 2012 SP2 and higher&lt;/a&gt;. This trace flag doesn&amp;rsquo;t give table variables the full statistics support which temporary tables have, but does try to make SQL Server smarter about the number of rows in the table variable.&lt;/p&gt;
&lt;p&gt;Disclaimer: changing from table variables to temporary tables doesn&amp;rsquo;t &lt;em&gt;always&lt;/em&gt; make things faster. I wasn&amp;rsquo;t doing live troubleshooting here and I didn&amp;rsquo;t have actual execution plans&amp;ndash; it&amp;rsquo;s possible that the rowsets are small and the table variables were doing well. You never know until you test!&lt;/p&gt;
&lt;h2 id="sometimes-you-should-just-take-out-a-tablock"&gt;Sometimes you should just take out a tablock&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t think this is the case for the person asking this question, but there are some cases when you just want to go ahead and take out an exclusive lock on a table. Not only can it simplify the number of locks for the table, but it can help &lt;a href="https://technet.microsoft.com/en-us/library/dd425070(v=sql.100).aspx"&gt;make data loading more efficient&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Should I Upgrade to SQL Server 2016? (Dear SQL DBA Episode 22)</title><link>https://kendralittle.com/2016/11/17/should-i-upgrade-to-sql-server-2016-dear-sql-dba-episode-22/</link><pubDate>Thu, 17 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/17/should-i-upgrade-to-sql-server-2016-dear-sql-dba-episode-22/</guid><description>&lt;p&gt;It&amp;rsquo;s a big week for SQL Server! And it&amp;rsquo;s the perfect week to talk about this week&amp;rsquo;s question, which is about explaining to your management why it&amp;rsquo;s worth it to upgrade to SQL Server 2016, and which features you can use right away.&lt;/p&gt;
&lt;p&gt;Watch the 24 minute video, scroll down to read the article, or &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;subscribe to the podcast&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/pLA-zpL-SRo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Three different people asked me a variation of this question recently at the SQL PASS Summit:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;We recently got budget to upgrade our SQL Server. My manager wants us to go with SQL Server 2014, because 2016 is so new. How can I convince management that 2016 is better?&lt;/p&gt;
&lt;p&gt;Lucky DBA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As of yesterday, you have more reasons than ever to go with SQL Server 2016.&lt;/p&gt;
&lt;p&gt;SQL Server 2016 Service Pack 1 was released, and not only do Service Packs give managers warm fuzzy feelings, this one was full of goodies.&lt;/p&gt;
&lt;h2 id="sql-server-2016-service-pack-1-adds-more-features-to-standard-edition-plus-web-express-and-local-db"&gt;SQL Server 2016 Service Pack 1 adds more features to Standard Edition (plus Web, Express, and Local DB)&lt;/h2&gt;
&lt;p&gt;I know most of y&amp;rsquo;all care about Standard Edition.&lt;/p&gt;
&lt;p&gt;With SP1, you can use all sorts of (formerly) super-expensive features like data compression, partitioning, Columnstore, Change Data Capture, Polybase, and more in Standard Edition.&lt;/p&gt;
&lt;p&gt;A few features have scalability caps in &amp;ldquo;lower&amp;rdquo; editions. There&amp;rsquo;s a memory limit for In-Memory OLTP (aka Hekaton), and Columnstore. Columnstore also has restrictions on parallelism.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t &lt;em&gt;every&lt;/em&gt; feature. Transparent Data Encryption and licensing for high-availability features hasn&amp;rsquo;t changed. Memory and CPU limits for editions haven&amp;rsquo;t changed either: Enterprise Edition is still needed for scalability and HA/DR.&lt;/p&gt;
&lt;p&gt;But overall, you get way more bang for your licensing buck in Standard Edition in SQL Server 2016 SP1.&lt;/p&gt;
&lt;p&gt;Or, in the case of Express Edition, you get more for free.&lt;/p&gt;
&lt;p&gt;Read the list of features by edition here: &lt;a href="https://www.microsoft.com/en-us/sql-server/sql-server-editions"&gt;https://www.microsoft.com/en-us/sql-server/sql-server-editions&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="quick-dba-wins-to-start-using-in-standard-edition"&gt;Quick DBA wins to start using in Standard Edition&lt;/h2&gt;
&lt;p&gt;Your management may ask, &amp;ldquo;which of these features can you use without code changes? And how much will they help?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a great question.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Database snapshots&lt;/strong&gt; can be immediately useful as part of your release process. You take a database snapshot before deploying a change, use it for verification, if needed, and drop it after the change is done. You incur write overhead for modifications used while the snapshot exists, but it doesn&amp;rsquo;t copy the whole database.
&lt;ul&gt;
&lt;li&gt;Warning: be careful jumping on the bandwagon of reverting to snapshots - that can have some gotchas. &lt;a href="http://www.sqlskills.com/blogs/paul/bug-reverting-from-a-database-snapshot-shrinks-the-transaction-log-to-0-5mb/"&gt;See Paul Randal&amp;rsquo;s post&lt;/a&gt; and &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/730113/revert-to-database-snapshot-looses-ldf-file-settings"&gt;this Connect Item&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data compression&lt;/strong&gt; can make better use of your storage and memory.
&lt;ul&gt;
&lt;li&gt;Fine print: don&amp;rsquo;t just compress all your indexes. You need to determine which tables might benefit, and which type of compression to use. There are CPU tradeoffs. Start with &lt;a href="https://technet.microsoft.com/en-us/library/dd894051"&gt;the Microsoft Whitepaper on Data Compression&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Table Partitioning - maybe&lt;/strong&gt;. Technically, you can implement table partitioning without a bunch of code changes. But in practice, you frequently do need to tune or rewrite some queries because of quirks as to how things like TOP or GROUP BY might behave differently. For tables that are sensitive to read performance, it usually takes both developers and DBAs to implement partitioning. However, you may have some tables which are easier wins&amp;ndash; like a table you almost exclusively write to for logging purposes, where table partitioning could be useful for truncating partitions instead of running deletes.
&lt;ul&gt;
&lt;li&gt;Disclaimer: I still very much claim that table partitioning is NOT a feature for query performance - it&amp;rsquo;s a tool for managing data. &lt;a href="https://kendralittle.com/2016/05/03/why-table-partitioning-doesnt-speed-up-query-performance-video/"&gt;Watch a free video on the details here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security-can-be-pretty-persuasive"&gt;Security can be pretty persuasive&lt;/h2&gt;
&lt;p&gt;When it comes to Standard Edition, the biggest change with 2016 SP1 is that &lt;a href="https://msdn.microsoft.com/en-us/library/mt163865.aspx"&gt;Always Encrypted is now available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your database stores anything like credit card numbers or social security numbers, you want this. You REALLY want this if you&amp;rsquo;re the DBA, because your life is simpler if there&amp;rsquo;s no way you could exploit that data. Think of this as a really nice protective vault for your data kryptonite.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: there are other security features in 2016 that may also be attractive, like &lt;a href="https://msdn.microsoft.com/en-us/library/mt130841.aspx"&gt;Dynamic Data Masking&lt;/a&gt;. They were available in Standard Edition as of RTM, but now are available in Web, Express, and Local DB.&lt;/p&gt;
&lt;p&gt;Fine print: Transparent Data Encryption (TDE) is still an Enterprise Edition feature.&lt;/p&gt;
&lt;h2 id="how-id-start-talking-about-in-memory-oltp"&gt;How I&amp;rsquo;d start talking about In-Memory OLTP&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQLServerExpressEdition-300x300.png"
alt="sqlserverexpressedition" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Well, you can, but you might break a few things.&lt;/p&gt;
&lt;p&gt;In-Memory OLTP, aka Hekaton, has a memory cap in the &amp;ldquo;lower&amp;rdquo; editions of 25% of the Buffer Pool Memory Limit. For Standard Edition, you&amp;rsquo;ll be limited to 32GB of memory for In-Memory tables, and when you run out of memory, things get real dicy.&lt;/p&gt;
&lt;p&gt;So you&amp;rsquo;ve got to be careful. But you&amp;rsquo;ve got to be careful even in Enterprise Edition, too&amp;ndash; because your hardware doesn&amp;rsquo;t have an infinite amount of memory. Even in EE, you have to learn to set up monitoring of how much memory is being used by In-Memory tables, alert when it&amp;rsquo;s getting low, and learn how to adjust it.&lt;/p&gt;
&lt;p&gt;Having In-Memory tables in Standard Edition gives you a much better place to learn.&lt;/p&gt;
&lt;p&gt;I would look for less critical applications that might have a good use case for In-Memory tables. Applications where it&amp;rsquo;s not a disaster if you have an outage. You need something that has a lot of writes to make it worth your while for the experiment.&lt;/p&gt;
&lt;p&gt;Logging databases where you don&amp;rsquo;t have to retain a ton of history come to mind&amp;ndash; I&amp;rsquo;ve worked with a bunch of apps that can flip verbose logging to a database on and off, and the app is designed to keep going even if the logging database goes off the farm.&lt;/p&gt;
&lt;p&gt;Essentially, you now have room to be creative and cautious with this feature. That&amp;rsquo;s gold.&lt;/p&gt;
&lt;h2 id="what-about-columnstore"&gt;What about Columnstore?&lt;/h2&gt;
&lt;p&gt;For Columnstore, there&amp;rsquo;s the same memory limit as for In-Memory tables: 25% of the Buffer Pool Limit for that Edition. Plus, Standard Edition is limited to 2 cores for parallel queries, Web and Express just get a single thread.&lt;/p&gt;
&lt;p&gt;This is a bit easier to play with as writes don&amp;rsquo;t stop when you run out of memory (unless it&amp;rsquo;s Clustered Columnstore on In-Memory OLTP). Reading Columnstore data from disk just isn&amp;rsquo;t as fast as it is to read it from Memory.&lt;/p&gt;
&lt;p&gt;You also have to balance out making sure the overheads of writes to a Columnstore index aren&amp;rsquo;t slowing you down (and that you can monitor this), and that you&amp;rsquo;re maintaining the index properly.&lt;/p&gt;
&lt;p&gt;For Columnstore, look for relatively narrow tables that have many millions of rows. I say narrow because you&amp;rsquo;ve got limited memory and parallelism to burn for this. And Columnstore shines when you&amp;rsquo;ve got many millions of rows to compress.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really not unusual to have many millions of rows in OLTP tables anymore, and to have a diverse amount of queries hitting them. OLTP tables are often narrow as well, so even with the limits, I see this as a big deal for Standard Edition to get this feature.&lt;/p&gt;
&lt;h2 id="sql-server-2016-has-query-store-all-editions"&gt;SQL Server 2016 has Query Store (all editions)&lt;/h2&gt;
&lt;p&gt;This hasn&amp;rsquo;t changed, &lt;em&gt;but it was already awesome&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Query Store gives you a way to track  your query plans along with metrics on query resource usage and execution time. So you can do things like see if adding a filtered nonclustered Columnstore index made things faster&amp;hellip; or oops, if it made things slower.&lt;/p&gt;
&lt;p&gt;Query Store is a fantastic feature for DBAs and Developers. It helps DBAs and Developers work better together, because they aren&amp;rsquo;t trying to save as many giant XML strings for query text and plans in spreadsheets anymore.&lt;/p&gt;
&lt;p&gt;Before yesterday, it was one of my biggest reasons to argue that a SQL Server 2016 upgrade is far more attractive, even for Standard Edition. Now it&amp;rsquo;s just another item on the list.&lt;/p&gt;
&lt;h2 id="youve-still-gotta-test-it"&gt;You&amp;rsquo;ve still gotta test it&lt;/h2&gt;
&lt;p&gt;Things can go wrong in service packs. You&amp;rsquo;ve got to test any upgrade, even if it&amp;rsquo;s full of goodies.&lt;/p&gt;
&lt;h2 id="2016-isnt-the-new-kid-anymore-meet-sql-server-vnext-ctp-1"&gt;2016 isn&amp;rsquo;t the new kid anymore. Meet SQL Server v.Next CTP 1&lt;/h2&gt;
&lt;p&gt;This train is picking up speed.&lt;/p&gt;
&lt;p&gt;SQL Server v.Next CTP1 is now available for download on Windows, Linux, and even Mac (via Docker containers).&lt;/p&gt;
&lt;p&gt;Check it out online here: &lt;a href="https://www.microsoft.com/en-us/evalcenter/evaluate-sql-server-vnext-ctp"&gt;https://www.microsoft.com/en-us/evalcenter/evaluate-sql-server-vnext-ctp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So it&amp;rsquo;s not like 2016 is the &amp;ldquo;new version&amp;rdquo; anymore, anyway.&lt;/p&gt;</description></item><item><title>SQL Server 2016 SP1: Features Added to Standard, Web, Express, Local DB Editions</title><link>https://kendralittle.com/2016/11/16/sql-server-2016-sp1-features-added-to-standard-web-express-local-db-editions/</link><pubDate>Wed, 16 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/16/sql-server-2016-sp1-features-added-to-standard-web-express-local-db-editions/</guid><description>&lt;p&gt;Wouldn&amp;rsquo;t it be awesome if you could develop your application for a small SQL Server using the same features that you intend to use for scale?&lt;/p&gt;
&lt;p&gt;And wouldn&amp;rsquo;t it be &lt;em&gt;more awesome&lt;/em&gt; if you could start using bleeding edge features like In-Memory OLTP on some of your less-risky, smaller databases first?&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/That-Time-SQL-Server-Gave-You-A-Pony-300x300.png"
alt="that-time-sql-server-gave-you-a-pony" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="in-the-past-cost-inhibitedfeature-adoption"&gt;In the past, cost inhibited feature adoption&lt;/h2&gt;
&lt;p&gt;This has been tough in the past, because SQL Server limits which Edition can use specific programmability features. Enterprise Edition gets all the goodies, and &lt;a href="https://www.microsoft.com/en-us/sql-server/sql-server-2016-pricing"&gt;Enterprise costs more&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enterprise Edition is ~$7,000 USD/core (minimum 4 cores per socket, sold in 2 core packs)&lt;/li&gt;
&lt;li&gt;Standard Edition is ~$1,800 USD/core (minimum 4 cores per socket, sold in 2 core packs / also available for purchase by Client Access License)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these prices, developers cant&amp;rsquo;t usually afford to use Enterprise Edition features on new, small projects. And they were forced to introduce cutting edge EE features into the most critical databases first&amp;ndash; because the least critical databases don&amp;rsquo;t get those licensing dollars. Software vendors often have to maintain two versions of their SQL Server codebase: one for Standard Edition customers, and one for Enterprise Edition customers.&lt;/p&gt;
&lt;p&gt;That changes today.&lt;/p&gt;
&lt;p&gt;Today is the &lt;a href="https://connectevent.microsoft.com/"&gt;Microsoft Connect()&lt;/a&gt; online developer conference. It&amp;rsquo;s also the day that &lt;a href="https://blogs.msdn.microsoft.com/sqlreleaseservices/sql-server-2016-service-pack-1-sp1-released/"&gt;SQL Server 2016 Service Pack 1&lt;/a&gt; is dropping. SP1 includes some amazing licensing changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/download/details.aspx?id=54276"&gt;Download SQL Server 2016 SP 1 here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="data-management-features-added-to-standard-express-web-and-mostly-local-db-editions-starting-with-sql-server-2016-sp1"&gt;Data Management Features added to Standard, Express, Web, and (mostly) Local DB Editions starting with SQL Server 2016 SP1&lt;/h2&gt;
&lt;p&gt;Developers will now be able to use far more features in production, whether or not they&amp;rsquo;re using Enterprise Edition. &lt;a href="https://www.microsoft.com/en-us/sql-server/sql-server-editions"&gt;These features are now available in &amp;ldquo;lower&amp;rdquo; editions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve noted usage &amp;ldquo;caps&amp;rdquo; as I understand them from initial information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Table Partitioning&lt;/li&gt;
&lt;li&gt;Data Compression&lt;/li&gt;
&lt;li&gt;Columnstore Indexes
&lt;ul&gt;
&lt;li&gt;Standard Edition limits DOP to 2&lt;/li&gt;
&lt;li&gt;Web / Express limit DOP to 1.&lt;/li&gt;
&lt;li&gt;Memory limited to 25% Buffer Pool limit for each non-EE edition (so you get 32GB for Standard Edition)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In-Memory OLTP
&lt;ul&gt;
&lt;li&gt;Memory limited to 25% Buffer Pool limit for each non-EE edition (so you get 32GB for Standard Edition)&lt;/li&gt;
&lt;li&gt;Not in Local DB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Distributed Partitioned Views (writeable)&lt;/li&gt;
&lt;li&gt;Multiple Filestream Containers&lt;/li&gt;
&lt;li&gt;Change Data Capture
&lt;ul&gt;
&lt;li&gt;Not in Express or Local DB, as this requires SQL Server Agent, which is not present there&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Database Snapshots&lt;/li&gt;
&lt;li&gt; PolyBase
&lt;ul&gt;
&lt;li&gt;Exception: not in Local DB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security-features-added-to-standard-express-web-and-mostly-local-db-editions-starting-with-sql-server-2016-sp1"&gt;Security Features added to Standard, Express, Web, and (mostly) Local DB Editions starting with SQL Server 2016 SP1&lt;/h2&gt;
&lt;p&gt;At this time I don&amp;rsquo;t know of any limitations on these features, or differences from Enterprise. It&amp;rsquo;s very cool to see SQL Server making enterprise grade security features available to everyone, in every edition.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auditing (some)&lt;/li&gt;
&lt;li&gt;Always Encrypted&lt;/li&gt;
&lt;li&gt;Row-Level Security
&lt;ul&gt;
&lt;li&gt;Has been available in Standard in 2016, now in Web, Express, Local DB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dynamic Data Masking
&lt;ul&gt;
&lt;li&gt;Has been available in Standard in 2016, now in Web, Express, Local DB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="did-the-price-for-standard-edition-go-up"&gt;Did the price for Standard Edition go up?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Dev-Environment-300x300.png"
alt="dev-environment" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Nope. No pricing changes. Just wider feature availability!&lt;/p&gt;
&lt;h2 id="will-people-still-need-to-buy-enterprise-edition"&gt;Will people still need to buy Enterprise Edition?&lt;/h2&gt;
&lt;p&gt;Yes. Scalability limits for edition aren&amp;rsquo;t changing. Enterprise still gets you more memory and more CPUs to scale your workload.&lt;/p&gt;
&lt;h2 id="fine-printnot-all-features-have-licensing-changes"&gt;Fine Print: not all features have licensing changes&lt;/h2&gt;
&lt;p&gt;The clever reader may have noticed that I haven&amp;rsquo;t mentioned AlwaysOn Availability Groups, Transparent Data Encryption, Database Mirroring, or Peer-to-Peer Replication. No licensing changes have been announced for those features, or for services like SSAS or SSRS.&lt;/p&gt;
&lt;p&gt;This is a huge licensing improvement, and it&amp;rsquo;s targeted at how you architect your schema and your codebase, and how you secure your data. But it doesn&amp;rsquo;t touch &lt;em&gt;everything.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="dont-worry-developer-edition-still-acts-like-enterprise"&gt;Don&amp;rsquo;t worry, Developer Edition still acts like Enterprise&lt;/h2&gt;
&lt;p&gt;Note that these changes don&amp;rsquo;t apply to Developer Edition. It continues to have all the features of Enterprise Edition, and it&amp;rsquo;s free (aww yeah), but &lt;a href="https://kendralittle.com/2016/07/12/is-user-acceptance-testing-covered-under-developer-edition/"&gt;it&amp;rsquo;s only for non-production environments&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="seems-like-a-great-time-to-upgrade-to-2016-doesnt-it"&gt;Seems like a great time to upgrade to 2016, doesn&amp;rsquo;t it?&lt;/h2&gt;
&lt;p&gt;Traditionally, managers like to wait until Service Pack 1 comes out before they get serious about upgrading to a new SQL Server version. You&amp;rsquo;ve got an especially good reason to talk about upgrades with this one!&lt;/p&gt;
&lt;h2 id="ps-you-try-out-sql-server-vnext-on-windows-and-linux-too"&gt;PS: you try out SQL Server v.Next on Windows and Linux, too&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s so much cool news today that I&amp;rsquo;m weirdly including this as a final note. The first preview of SQL Server v.Next is dropping today. You can run it on Windows. You can run it on Linux. You can run it in a Docker container on a Mac.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/evalcenter/evaluate-sql-server-vnext-ctp"&gt;Download v.Next CTP1 it here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wowzers.&lt;/p&gt;</description></item><item><title>Downgrading the SQL Server Edition of a Dev Environment</title><link>https://kendralittle.com/2016/11/15/downgrading-the-sql-server-edition-of-a-dev-environment/</link><pubDate>Tue, 15 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/15/downgrading-the-sql-server-edition-of-a-dev-environment/</guid><description>&lt;p&gt;I got a great question about Edition downgrades recently.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have discovered a tranche of potential money saving by replacing SQL Server Enterprise Edition with SQL Server Developer Edition where appropriate. All of the checks have been made - i.e. the Servers are truly Development servers, with nothing Production going anywhere near (either data or people).&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s the simplest way of changing a SQL Server in this way? It looks like an uninstall / re-install but there&amp;rsquo;s an awful lot of objects on that Server - Databases, Security, Linked Servers, SSIS, Triggers, so a lot of work. Some people on the Internet suggest copying the system databases before re-installing to the same patch level then copying the previous system databases back in.&lt;/p&gt;
&lt;p&gt;Hoping to pull off the Tablecloth trick&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whee! It&amp;rsquo;s always so much fun when you can save a lot of licensing costs.&lt;/p&gt;
&lt;p&gt;When an environment is being used for development, it can be licensed with free Developer Edition (&lt;a href="https://kendralittle.com/2016/07/12/is-user-acceptance-testing-covered-under-developer-edition/"&gt;even if you do user acceptance testing in it&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;And Developer Edition has all the features of Enterprise Edition. Pretty great deal, eh?&lt;/p&gt;
&lt;h2 id="why-not-just-use-skuupgrade"&gt;Why not just use SKUUPGRADE?&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Hocus-Pocus-Downgrade-300x300.png"
alt="hocus-pocus-downgrade" width="230"&gt;
&lt;/figure&gt;
There&amp;rsquo;s now a way to upgrade editions in the SQL Server installation interface, but it used to need to be done with the command line using a /SKUUPGRADE parameter, so a lot of people still use that term online.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Evaluation Edition, you can often change to other editions quite easily.&lt;/p&gt;
&lt;p&gt;But you can&amp;rsquo;t easily downgrade your editions, and there&amp;rsquo;s also limitations on changing editions when you&amp;rsquo;re using a cluster. Microsoft has a list of &lt;a href="https://msdn.microsoft.com/en-us/library/ms143393.aspx"&gt;Supported Version and Edition Upgrades here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Basically there&amp;rsquo;s no supported path to use the built-in tools to quickly change from Enterprise to Developer Edition.&lt;/p&gt;
&lt;h2 id="im-careful-about-doing-things-that-are-unsupported"&gt;I&amp;rsquo;m careful about doing things that are unsupported&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Unsupported&amp;rdquo; isn&amp;rsquo;t always terrible. It doesn&amp;rsquo;t mean &amp;ldquo;illegal&amp;rdquo;. It just means that Microsoft isn&amp;rsquo;t going to help you if something goes wrong because of what you did.&lt;/p&gt;
&lt;p&gt;Technically, running the &amp;ldquo;DBCC PAGE&amp;rdquo; command is unsupported, and &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/776144/dbcc-page-incorrect-output-with-filtered-indexes"&gt;running it can even sometimes cause stack dumps&lt;/a&gt;. I still blog about it and run it sometimes, I&amp;rsquo;m just careful.&lt;/p&gt;
&lt;p&gt;In this case, doing &lt;a href="https://www.mssqltips.com/sqlservertip/3079/downgrade-from-sql-server-enterprise-edition-to-standard-edition/"&gt;an unsupported downgrade&lt;/a&gt; &lt;em&gt;might&lt;/em&gt; be just fine. I wouldn&amp;rsquo;t like managing the environment afterward because it&amp;rsquo;s such a significant unsupported action &amp;ndash; if I choose to take a system-database copying shortcut, am I going to be haunted by that for a long while afterward when anything goes wrong in the environment?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been burned by things like that over the years, so I&amp;rsquo;m a bit careful.&lt;/p&gt;
&lt;h2 id="if-it-was-my-environment-i-would-want-to-do-fresh-installs"&gt;If it was my environment, I would want to do fresh installs&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Developer-Edition-Goats-300x300.png"
alt="developer-edition-goats" width="230"&gt;
&lt;/figure&gt;
Development environments have a way of becoming pretty messy. That&amp;rsquo;s usually OK, and it&amp;rsquo;s part of the nature of the beast, but when a Dev environment goes along for many years just being upgraded and patched and modified by many developers, eventually nobody knows what it&amp;rsquo;s set up like anymore.&lt;/p&gt;
&lt;p&gt;And then  you start hitting issues where you deploy to production, and it doesn&amp;rsquo;t work there, but it worked fine in Dev. Because the dev environment doesn&amp;rsquo;t resemble production much anymore.&lt;/p&gt;
&lt;p&gt;For this reason, I&amp;rsquo;m a big fan of being able to rebuild dev from scratch periodically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I want the dev environments to be installed as much like production as possible&lt;/li&gt;
&lt;li&gt;I want to have dev environments documented and configured as much as possible, so that if we had to re-install fresh after a disaster, we&amp;rsquo;d be OK &amp;ndash; and everything about the environment configuration is &amp;ldquo;known&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Dev environment OS&amp;rsquo;s tend to lag behind production, and doing a fresh install is a good chance to test &amp;ldquo;ahead&amp;rdquo; and get to a newer version in dev before rolling it out to production&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="but-i-wouldnt-want-to-do-the-uninstall"&gt;But I wouldn&amp;rsquo;t want to do the uninstall!&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a huge pain to make a big modification in-place on an environment. Even dev environments, because things don&amp;rsquo;t always work in dev and sometimes it&amp;rsquo;s fine: so if you change the environment in place, afterward you have a hard time figuring out if your change broke it, or if it was just already broken.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s &lt;em&gt;so&lt;/em&gt; much easier when you have the &amp;ldquo;before&amp;rdquo; around to compare to the &amp;ldquo;after&amp;rdquo;, and you&amp;rsquo;re doing a switcharoo rather than changing what&amp;rsquo;s in place.&lt;/p&gt;
&lt;p&gt;This is one of the things that&amp;rsquo;s fantastic about virtualization - being able to set up a new environment and keep the old around on slow hardware for a while. When things don&amp;rsquo;t work, you go look at the old one to see what you missed.&lt;/p&gt;
&lt;p&gt;So I would want to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Spin up a new virtualized environment&lt;/li&gt;
&lt;li&gt;Choose OS version and cluster configuration carefully if I use them before deploying&lt;/li&gt;
&lt;li&gt;Automate SQL Server installs and use slipstreaming for SPs/Cumulative updates&lt;/li&gt;
&lt;li&gt;Look at PowerShell tools to capture and deploy current environment configuration - things like: &lt;a href="https://dbatools.io/functions/"&gt;https://dbatools.io/functions/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check in all my scripts and documentation to source code that&amp;rsquo;s backed up offsite for future use&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="would-you-go-the-long-route"&gt;Would &lt;em&gt;you&lt;/em&gt; go the long route?&lt;/h2&gt;
&lt;p&gt;My way of approaching this is definitely not the simplest or the fastest. It&amp;rsquo;s just the one that results in an environment I&amp;rsquo;m happier living with.&lt;/p&gt;
&lt;p&gt;What about you, Internet Reader? Have you used shortcuts for downgrading editions and had good experiences? Bad experiences?&lt;/p&gt;</description></item><item><title>Filtered Indexes: Rowstore vs Nonclustered Columnstore</title><link>https://kendralittle.com/2016/11/10/filtered-indexes-rowstore-vs-nonclustered-columnstore/</link><pubDate>Thu, 10 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/10/filtered-indexes-rowstore-vs-nonclustered-columnstore/</guid><description>&lt;p&gt;SQL Server has two types of filtered indexes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &amp;ldquo;classic&amp;rdquo; filtered nonclustered rowstore index, introduced in SQL Server 2008, available in all editions&lt;/li&gt;
&lt;li&gt;The newfangled filtered nonclustered columnstore index, introduced in SQL Server 2016, available in Enterprise Edition&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These two filtered indexes are very different - and the SQL Server optimizer can use them very differently!&lt;/p&gt;
&lt;p&gt;While classic filtered nonclustered rowstore indexes must reliably &amp;ldquo;cover&amp;rdquo; parts of the query to be used to the optimizer, filtered nonclustered columnstore indexes may be combined with other indexes to produce a plan returning a larger range of data.&lt;/p&gt;
&lt;p&gt;This sounds a little weird. I&amp;rsquo;ll show you what I mean using the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters database&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="filtered-nonclustered-rowstore-indexes-filtered-indexes"&gt;Filtered nonclustered rowstore indexes (&amp;ldquo;Filtered Indexes&amp;rdquo;)&lt;/h2&gt;
&lt;p&gt;A filtered index is a nonclustered rowstore index with a &amp;ldquo;where&amp;rdquo; clause. This index contains only rows from Sales.Invoices which were last edited before February 1, 2013:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_nc_filter_LT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Invoices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2013-02-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SQL Server may use this index if I run it for a query that also specifies LastEditedWhen &amp;lt; &amp;lsquo;2013-02-01&amp;rsquo; (although possibly not if my query is parameterized and may be used for a date outside this range).&lt;/p&gt;
&lt;p&gt;What if I am querying all CustomerIds, and I force SQL Server to use this index with a hint?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Invoices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ix_nc_filter_LT&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SQL Server could potentially pick up some of the rows from the filtered index, then find the rest of the rows in the base table and combine them. It&amp;rsquo;d be expensive, but it&amp;rsquo;s theoretically possible.&lt;/p&gt;
&lt;p&gt;However, SQL Server can&amp;rsquo;t. Instead, I get this error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 8622, Level 16, State 1, Line 21
Query processor could not produce a query plan because of the hints defined in this query. Resubmit the query without specifying any hints and without using SET FORCEPLAN.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My query wants a larger range of data than is in my filtered rowstore index, and SQL Server won&amp;rsquo;t use the filtered rowstore index and then go find the rest of the data in another index. The optimizer just isn&amp;rsquo;t written to do this.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve been used to this for years with filtered indexes. &lt;em&gt;But filtered nonclustered columnstore indexes behave differently!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="filtered-nonclustered-columnstore-indexes-filtered-ncci"&gt;Filtered nonclustered columnstore indexes (&amp;ldquo;Filtered NCCI&amp;rdquo;)&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create a filtered nonclustered columnstore index on the same table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMNSTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_ncci_filter_LT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Invoices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LastEditedWhen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2013-02-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m not saying this little demo table needs a nonclustered columnstore, I&amp;rsquo;m just reusing it for simplicity.&lt;/p&gt;
&lt;p&gt;Now, I force SQL Server to use this index to get all the CustomerIDs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Invoices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ix_ncci_filter_LT&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This time, the query doesn&amp;rsquo;t fail to get a plan! I get a plan, and I get all the 70,510 rows back. The execution plan looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/FilteredNonclusteredColumnstore-Combined.jpg"
alt="filterednonclusteredcolumnstore-combined"&gt;
&lt;/figure&gt;
&lt;p&gt;This isn&amp;rsquo;t an awesome plan. SQL Server scanned the columnstore index, then scanned the clustered index of the table to find the rows that weren&amp;rsquo;t in the columnstore index, then combined them. It did this because I forced it to use the columnstore hint.&lt;/p&gt;
&lt;p&gt;But SQL Server &lt;em&gt;can&lt;/em&gt; make this plan. SQL was able to do this because it understands the filter in the nonclustered columnstore index. Hover over the clustered index scan in the plan, and you can see it figured out how to find the rest of the data in the clustered index:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/FilteredNonclusteredColumnstore-Combined-Predicate.jpg"
alt="filterednonclusteredcolumnstore-combined-predicate"&gt;
&lt;/figure&gt;
&lt;h2 id="why-are-filtered-nonclustered-columnstore-indexes-smarter"&gt;Why are filtered nonclustered columnstore indexes smarter?&lt;/h2&gt;
&lt;p&gt;Columnstore indexes shine when it comes to scanning and aggregating lots of data. While nonclustered columnstore indexes are updatable in SQL Server 2016, it&amp;rsquo;s expensive to maintain them.&lt;/p&gt;
&lt;p&gt;SQL Server is smarter about optimizing plans with filtered nonclustered columnstore indexes so you can design your filter so that &amp;ldquo;cold&amp;rdquo; data which is unlikely to be modified is in the columnstore index. This makes it cheaper to maintain. The optimizer has the ability to use the filtered NCCI and combine it with other indexes behind the scenes.&lt;/p&gt;
&lt;p&gt;You do want to be careful with your filter and make sure that it doesn&amp;rsquo;t have to do a clustered index scan every time it&amp;rsquo;s going to do this trick, of course!&lt;/p&gt;
&lt;p&gt;Read more about this feature on the SQL Server database engine blog in Sunil Agarwal&amp;rsquo;s post, &amp;ldquo;&lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/03/06/real-time-operational-analytics-filtered-nonclustered-columnstore-index-ncci/"&gt;Real-Time Operational Analytics: Filtered nonclustered columnstore index (NCCI)&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Shrinking SQL Server Data Files - Best Practices, and Why It Sucks</title><link>https://kendralittle.com/2016/11/08/shrinking-sql-server-data-files-best-practices-and-why-it-sucks/</link><pubDate>Tue, 08 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/08/shrinking-sql-server-data-files-best-practices-and-why-it-sucks/</guid><description>&lt;p&gt;I&amp;rsquo;ve gotten a few questions about shrinking SQL Server data files lately. What&amp;rsquo;s the best way to get shrink to run? And why might it fail in some cases?&lt;/p&gt;
&lt;p&gt;Traditionally, every time you ask a DBA how to make shrinking suck less, they start ranting how shrinking is bad and you just shouldn&amp;rsquo;t do it. Sometimes it sounds kinda angry.&lt;/p&gt;
&lt;p&gt;What people are trying to say is that shrinking data files is generally slow, frustrating, and painful for you.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/DBCC-SHRINKFILE-300x300.png"
alt="dbcc-shrinkfile" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="shrinking-data-files-sucks-and-you-dont-really-have-many-ways-to-make-it-suck-less"&gt;Shrinking data files sucks, and you don&amp;rsquo;t really have many ways to make it suck less&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what you&amp;rsquo;re up against, when it comes to shrinking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shrinking can cause blocking while it runs. Here&amp;rsquo;s a post I wrote a while back &lt;a href="https://www.brentozar.com/archive/2015/04/dbcc-shrinkfile-blocking-locks-in-sql-server/"&gt;with a demo script to reproduce the blocking&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Shrinking may stop running and not tell you why.
&lt;ul&gt;
&lt;li&gt;In one case, DBCC SHRINKFILE was stopping because it was hitting a deadlock and being declared the deadlock victim. That message didn&amp;rsquo;t show in the messages window for the session running SHRINKFILE though! Fun? (Not really.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Shrinking fragments your indexes - if the indexes are large and you run a rebuild command on them, you may just regrow the data files anyway.&lt;/li&gt;
&lt;li&gt;If shrink has to move around LOB data, it&amp;rsquo;s super slow. &lt;a href="http://www.sqlskills.com/blogs/paul/why-lob-data-makes-shrink-run-slooooowly-t-sql-tuesday-006/"&gt;Paul Randal explains why here&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;Note that you might hit this even if the data you &lt;em&gt;deleted&lt;/em&gt; doesn&amp;rsquo;t contain LOB data. If there are LOB pages closer to the end of the file, SQL will pick up those pages and move them towards the beginning of the file.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s not your fault that shrinking has all this baggage. You just want to have a smaller database. But these things are why you generally want to avoid shrinking whenever possible.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Data-grooming-300x150.png"
alt="data-grooming" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="most-senior-dbas-proactively-keep-free-space-in-the-database-and-regularly-archive-data"&gt;Most senior DBAs proactively keep free space in the database and regularly archive data&lt;/h2&gt;
&lt;p&gt;Planning beats shrinking, every day.&lt;/p&gt;
&lt;p&gt;Data growth and grooming should never be dictated by disk space. The data is more important in than the disk space!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regularly clean up data that&amp;rsquo;s truly no longer needed.
&lt;ul&gt;
&lt;li&gt;If you can have a nightly process that removes old data in small batches, rather than doing it once a quarter, that&amp;rsquo;s usually better for performance. It varies depending on when your database is in use, and whether your data removal process might block users.&lt;/li&gt;
&lt;li&gt;Sometimes it&amp;rsquo;s desirable for a business to remove data which is no longer needed quickly for legal reasons. This varies a lot by industry, though.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Measure data growth regularly, and start to estimate how much data is likely to grow in the future&lt;/li&gt;
&lt;li&gt;Keep free space in the database to allow for data growth without file growths.
&lt;ul&gt;
&lt;li&gt;This means proactively requesting more disk space and proactively growing the files. You can do it quarterly or once or twice a year &amp;ndash; whatever works best for you, but set up reminders and don&amp;rsquo;t skip it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Charting data growth and proactively managing the space ahead of time keeps you out of reactive &amp;ldquo;shrink mode&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It also makes you look good to your management to be on top of this!&lt;/p&gt;
&lt;h2 id="sometimes-you-do-have-to-shrink-data-files"&gt;Sometimes you do have to shrink data files&lt;/h2&gt;
&lt;p&gt;Sure, shrinking stinks, and you avoid it when you can. But sometimes you have a one-time archive of a lot of data. You know that you aren&amp;rsquo;t going to reuse the space in the next year, and it&amp;rsquo;s enough space that shrinking will make restoring the database elsewhere easier.&lt;/p&gt;
&lt;p&gt;In those cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider workarounds. Sometimes it&amp;rsquo;s less work to import the remaining data into a new database during an outage, depending on how much you&amp;rsquo;re removing and how much is left.
&lt;ul&gt;
&lt;li&gt;This could also allow you to carefully plan a nice filegroup and file layout in the new database.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Identify low use times you can run the shrink.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://msdn.microsoft.com/en-us/library/ms189493.aspx"&gt;DBCC SHRINKFILE&lt;/a&gt; and set a specific, targeted size for the file you&amp;rsquo;re shrinking.&lt;/li&gt;
&lt;li&gt;Watch your backup jobs, and make sure they&amp;rsquo;re succeeding and not taking way longer than normal.&lt;/li&gt;
&lt;li&gt;Plan to leave empty space in your data files to allow for growth over the next year, and to allow index rebuilds to work if needed after the shrink is done. No need to over-shrink and then re-grow.&lt;/li&gt;
&lt;li&gt;Watch for blocking if you don&amp;rsquo;t have an outage window&lt;/li&gt;
&lt;li&gt;If you need to know how long the shrink is going to take, restore a copy of the database elsewhere and test ahead of time to get an idea &amp;ndash; but it&amp;rsquo;s still going to be a rough estimate.
&lt;ul&gt;
&lt;li&gt;Knowing how much LOB data it&amp;rsquo;s going to have to move is really hard from the outside. Blocking makes a different as well, as does hardware and disk speed, so it&amp;rsquo;s really tough to estimate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Make sure you&amp;rsquo;re running &lt;a href="https://msdn.microsoft.com/en-us/library/ms176064.aspx"&gt;DBCC CHECKDB regularly&lt;/a&gt;. Because you should be doing that! (No, shrinking shouldn&amp;rsquo;t particularly cause corruption, but a little caution ain&amp;rsquo;t bad, either.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And maybe find a show to binge-watch on Netflix while your shrink is running. Something that just takes a couple of brain cells to watch, and which you wouldn&amp;rsquo;t mind pausing if things get funky.&lt;/p&gt;</description></item><item><title>Adaptive Query Processing (Dear SQL DBA Episode 21)</title><link>https://kendralittle.com/2016/11/03/whats-adaptive-query-processing-dear-sql-dba-episode-21/</link><pubDate>Thu, 03 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/03/whats-adaptive-query-processing-dear-sql-dba-episode-21/</guid><description>&lt;p&gt;Episode update, April 2017: Learn About Adaptive Query Processing from Joe Sack&lt;/p&gt;
&lt;p&gt;Microsoft shared a great video about Adaptive Query Processing, and you can learn about this new feature from Microsoft Program Manager Joe Sack. My original post below is full of speculation. Joe&amp;rsquo;s video is full of actual facts!&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: I've embedded Joe's video, which is published on the Microsoft Cloud Platform's YouTube Channel. I had less than nothing to do with making it. &lt;a href="https://www.youtube.com/watch?v=szTmo6rTUjM&amp;feature=youtu.be"&gt;Go give it a thumbs up to show them some love&lt;/a&gt;.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/szTmo6rTUjM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="and-now-for-my-original-episode-back-when-this-feature-was-first-announced"&gt;And now for my original episode, back when this feature was first announced&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m mixing things up a bit in this episode. I want to talk about a question that keynotes and sessions at the SQL PASS Summit got me thinking about last week. Let&amp;rsquo;s talk about Adaptive Query Processing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Watch the 24 minute video, scroll down to read the transcript, or &lt;a href="https://kendralittle.com/dearsqldba/"&gt;subscribe to the podcast&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/jO1z3n0TqNI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3 id="this-post-includes-a-lot-of-speculation"&gt;This post includes a lot of speculation&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m headed to the Microsoft MVP Summit next week. The cool thing about the MVP Summit is that you get to learn some things that aren&amp;rsquo;t public yet. The downside is that once you get some secret info, that closes off your ability to speculate a bit&amp;hellip; because you don&amp;rsquo;t want to speculate too close to something that is &amp;ldquo;secret&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Everything I&amp;rsquo;m talking about today was either revealed publicly last week at the Summit, or is speculation on my part (and is pure speculation, I have no privileged insights on this stuff).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll do my best to be completely clear about what&amp;rsquo;s speculation and what isn&amp;rsquo;t here.&lt;/p&gt;
&lt;h3 id="keynote-focus-predicting-the-future"&gt;Keynote focus: predicting the future&lt;/h3&gt;
&lt;p&gt;Perhaps speculation feels like the right topic today because Microsoft folks talked a lot about the importance of prediction in the keynotes at the PASS Summit last week.&lt;/p&gt;
&lt;p&gt;SQL Server 2016 features &lt;a href="https://msdn.microsoft.com/en-us/library/mt604845.aspx"&gt;R Services&lt;/a&gt;. This brings the ability to learn patterns and make predictions into the database engine.&lt;/p&gt;
&lt;p&gt;Using this new feature came up a lot in the keynote. And not just for performing predictions for a user application, either: there were quite a few references about using SQL Server&amp;rsquo;s predictive powers to make SQL Server &lt;em&gt;itself&lt;/em&gt; smarter.&lt;/p&gt;
&lt;p&gt;So what might that mean?&lt;/p&gt;
&lt;h3 id="were-used-to-sql-server-optimizing-a-query-before-it-runs"&gt;We&amp;rsquo;re used to SQL Server optimizing a query before it runs&lt;/h3&gt;
&lt;p&gt;When you execute a query, the SQL Server optimizer has to quickly analyze what all its options are for executing the query with the data structures it has at hand. It uses &amp;lsquo;statistics&amp;rsquo; to help it estimate how much data it will get back from each structure.&lt;/p&gt;
&lt;p&gt;It has a lot to figure out: what types of joins should it choose? Should it use a single core or multiple cores? How much memory should it allocate for operators that need to do things like sorting and creating hash tables in memory?&lt;/p&gt;
&lt;p&gt;It has to figure it out &lt;em&gt;fast&lt;/em&gt;. Every microsecond taking in optimizing a query is a microsecond the user is waiting.&lt;/p&gt;
&lt;h3 id="once-a-query-starts-executing-sql-server-doesnt-currently-do-re-optimization"&gt;Once a query starts executing, SQL Server doesn&amp;rsquo;t (currently) do &amp;ldquo;re-optimization&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Once the optimizer chooses a plan, the query goes off to the races. SQL Server doesn&amp;rsquo;t have the option for it to turn back.&lt;/p&gt;
&lt;p&gt;Some of us have wondered for a while if we might get a feature where SQL Server can change a query plan after it starts running if it looks like estimates from statistics weren&amp;rsquo;t accurate.&lt;/p&gt;
&lt;p&gt;Oracle has a feature called &amp;ldquo;&lt;a href="http://www.oracle.com/technetwork/database/bi-datawarehousing/twp-optimizer-with-oracledb-12c-1963236.pdf"&gt;Adaptive Query Optimization&lt;/a&gt;&amp;rdquo; which stretches the optimization process out into the query execution phase. Oracle can start a query with a &amp;ldquo;default plan.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m no Oracle expert, but here&amp;rsquo;s how their docs describe Adaptive Query Optimization:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once the query is running, if it looks like estimates were way off, it can change portions of the plan based on what it&amp;rsquo;s finding.&lt;/li&gt;
&lt;li&gt;It can change joins, parallelism, and even create &amp;ldquo;dynamic statistics&amp;rdquo; to get more detailed information where things looked fishy.&lt;/li&gt;
&lt;li&gt;Oracle can also use what it learns about rowcounts after a query executes to help it optimize future executions of that query.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m not going through this to suggest that SQL Server will implement the same features. But it can be useful to think about what competitors are doing in terms of optimization to open up our view a little when we&amp;rsquo;re thinking about what&amp;rsquo;s &lt;em&gt;possible&lt;/em&gt;. And of course, SQL Server can go beyond this.&lt;/p&gt;
&lt;h3 id="things-have-been-changing-in-azure-with-automatic-index-tuning-in-the-sql-database-advisor"&gt;Things have been changing in Azure with automatic index tuning in the SQL Database Advisor&lt;/h3&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Tuning-Forks-300x300.png"
alt="tuning-forks" width="230"&gt;
&lt;/figure&gt;
This isn&amp;rsquo;t your old Database Tuning Advisor. You have a newer option called (similarly) &lt;a href="https://azure.microsoft.com/en-us/documentation/articles/sql-database-advisor/"&gt;SQL Database Advisor&lt;/a&gt; when you use Azure SQL Database.&lt;/p&gt;
&lt;p&gt;The SQL Database Advisor in hosted databases can recommend indexes to create and drop, and it&amp;rsquo;ll note when queries aren&amp;rsquo;t parameterized or are getting a lot of recompiles to end up with the same plan.&lt;/p&gt;
&lt;p&gt;You have the option to tell the SQL Database Advisor to automatically manage indexes. In this case, it&amp;rsquo;ll not only apply the index changes but watch performance after it makes the change. If things get slower, it&amp;rsquo;ll revert the change.&lt;/p&gt;
&lt;p&gt;How well does this work in practice?&lt;/p&gt;
&lt;p&gt;Honestly, I have no idea :)&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m starting to get really curious after the Summit this year, so I&amp;rsquo;m planning to start exploring this more.&lt;/p&gt;
&lt;h3 id="announced-last-week-adaptivequery-processing"&gt;Announced last week: Adaptive Query Processing&lt;/h3&gt;
&lt;p&gt;I attended a session called &amp;ldquo;What&amp;rsquo;s New in Azure SQL Database?&amp;rdquo; at PASS last week. This was presented by &lt;a href="https://twitter.com/herdcats"&gt;Lindsey Allen&lt;/a&gt; and other program manager on the SQL Server Engineering team.&lt;/p&gt;
&lt;p&gt;There was a &lt;em&gt;lot&lt;/em&gt; of cool stuff discussed in the session, but two bullet points in particular jumped out at me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performance insight and auto-tuning&lt;/li&gt;
&lt;li&gt;Adaptive query processing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adaptive query processing is basically a subset of what&amp;rsquo;s being called &amp;ldquo;performance intelligence&amp;rdquo;. We saw a very cool demo video that explained that Adaptive Query Processing is focusing on three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Row estimates for &amp;ldquo;problematic subtrees&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Adjusting memory grants&lt;/li&gt;
&lt;li&gt;Fixing join types when needed&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="how-is-adaptive-query-processing-going-to-work"&gt;How is Adaptive Query Processing going to work?&lt;/h3&gt;
&lt;p&gt;I have no idea. This is a totally new area, and it was a fast moving session that quickly moved on to other new features.&lt;/p&gt;
&lt;p&gt;I got two somewhat conflicting ideas about how this might work, and I&amp;rsquo;m looking forward to sorting it out in the future.&lt;/p&gt;
&lt;p&gt;Count this all as pure speculation, because I may have a very skewed understanding of what I heard at this point.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;This might be based on collecting information by observing a workload of queries &amp;ndash; say, queries collected in Query Store&amp;ndash; and using R Services to find queries where optimization needs to be improved, then giving feedback for future runs of the query.
&lt;ul&gt;
&lt;li&gt;Simple example I can think of when it comes to memory grants: if SQL Server always requests a lot more memory than it actually uses for a frequent query, this could be learned and the grant could be reduced. This could help avoid low workspace query situations on very busy systems (aka RESOURCE_SEMAPHORE waits)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This might also involve some dynamic optimization at runtime. One slide I saw was talking about joins, and used the phrase &amp;ldquo;&lt;strong&gt;Defer the join choice until after the first join input has been scanned&lt;/strong&gt;.&amp;rdquo;
&lt;ul&gt;
&lt;li&gt;That sounds a lot like optimization may be stretching out into the execution of the query, right?&lt;/li&gt;
&lt;li&gt;I also saw the sentence &amp;ldquo;&lt;strong&gt;Materialize estimates for problematic subtrees&lt;/strong&gt;&amp;rdquo;, which sounds like getting extra statistics for parts of the plan where estimated rows and actual rows differ. But no idea yet if this could happen on first execution of the query or would be observed across a workload after a bunch of things have run.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="speculation-to-optimize-a-herd-workload-of-queries-wouldnt-query-store-need-wait-stats"&gt;Speculation: to optimize a &amp;ldquo;herd&amp;rdquo;/ workload of queries, wouldn&amp;rsquo;t Query Store need wait stats?&lt;/h3&gt;
&lt;p&gt;If I did understand correctly that Adaptive Query Optimization at least in part requires using data collected from a workload of queries and analyzing it in R, then the 2016 Query Store feature seems like it&amp;rsquo;d be a big part of the picture. Query Store collects runtime statistics and execution plans.&lt;/p&gt;
&lt;p&gt;But to do this well, wouldn&amp;rsquo;t the analysis also need to know why a query was slow? Perhaps it just couldn&amp;rsquo;t get started because it was waiting on a lock. That doesn&amp;rsquo;t necessarily mean it needs to have different joins or its memory grant changed.&lt;/p&gt;
&lt;p&gt;This is pure speculation, but &lt;em&gt;if&lt;/em&gt; Adaptive Query Processing uses Query Store data, this makes me think we might see Query Store collecting Wait Statistics sometime soon.&lt;/p&gt;
&lt;h3 id="will-adaptive-query-processing-be-cloud-only-or-part-of-boxed-sql-server"&gt;Will Adaptive Query Processing be Cloud-Only, or part of &amp;ldquo;boxed&amp;rdquo; SQL Server?&lt;/h3&gt;
&lt;p&gt;The session I was attending was specifically on Azure SQL Database.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t hear an announcement about whether this feature might be available outside of the cloud. But I also didn&amp;rsquo;t hear anything that sounded like it would prevent this feature from working in the the &amp;ldquo;install and manage it yourself&amp;rdquo; boxed version of SQL Server.&lt;/p&gt;
&lt;p&gt;A lot of times we don&amp;rsquo;t get a clear answer on this until they start to ship previews of new major versions of SQL Server &amp;ndash; so treat anything you hear as speculation unless it&amp;rsquo;s directly from a Microsoft Program Manager.&lt;/p&gt;
&lt;h3 id="you-can-sign-up-for-the-preview-of-adaptive-query-processing"&gt;You can sign up for the preview of Adaptive Query Processing&lt;/h3&gt;
&lt;p&gt;Check it out yourself! &lt;a href="https://aka.ms/AdaptiveQPPreview"&gt;https://aka.ms/AdaptiveQPPreview&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="got-your-own-speculations-or-even-gasp-some-facts"&gt;Got your own speculations? Or even (gasp) some facts?&lt;/h3&gt;
&lt;p&gt;Tell me all about it in the comments!&lt;/p&gt;</description></item><item><title>SQL Server Query Store - Filegroups and Adhoc Workloads</title><link>https://kendralittle.com/2016/11/01/sql-server-query-store-filegroups-and-adhoc-workloads/</link><pubDate>Tue, 01 Nov 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/11/01/sql-server-query-store-filegroups-and-adhoc-workloads/</guid><description>&lt;p&gt;A couple of questions on SQL Server 2016&amp;rsquo;s new Query Store feature came up in my recent pre-conference session on index tuning in SQL Server. I wasn&amp;rsquo;t 100% sure of the answer offhand, so I promised to follow up in a blog post.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/QueryStore-300x300.png"
alt="querystore" width="230"&gt;
&lt;/figure&gt;
Here are the questions:&lt;/p&gt;
&lt;h2 id="can-you-change-the-filegroup-where-query-store-keeps-its-data"&gt;Can you change the filegroup where Query Store keeps its data?&lt;/h2&gt;
&lt;p&gt;I thought there might be a trick to use a different filegroup for Query Store by using the default filegroup setting in SQL Server before enabling it, but NOPE!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/2565624/option-to-store-query-store-data-in-a-filegroup-other-than-primary"&gt;Please vote for this to be improved in this Connect Item&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(It only has 6 votes at the time of this writing! It needs more. And thanks to Derek Bell for emailing me the link to the Connect item.)&lt;/p&gt;
&lt;h2 id="what-happens-if-youre-using-optimize-for-adhoc-workloads-and-query-store"&gt;What happens if you&amp;rsquo;re using &amp;lsquo;Optimize for Adhoc Workloads&amp;rsquo; and Query Store?&lt;/h2&gt;
&lt;p&gt;I was pretty sure I&amp;rsquo;d read a post from Grant Fritchey about this, and &lt;a href="http://www.scarydba.com/2016/03/28/query-store-and-optimize-for-ad-hoc/"&gt;sure enough, he covers the behavior here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Spoiler: Enabling Optimize for Adhoc doesn&amp;rsquo;t prevent the plan from being stored in Query Store on first run.&lt;/p&gt;
&lt;p&gt;Grant has a bunch of great posts on Query Store. &lt;a href="http://www.scarydba.com/tag/query-store/"&gt;Check them all out here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Thoughts from the SQLPASS Summit Wednesday Keynote, 2016</title><link>https://kendralittle.com/2016/10/26/thoughts-from-the-sqlpass-summit-wednesday-keynote-2016/</link><pubDate>Wed, 26 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/26/thoughts-from-the-sqlpass-summit-wednesday-keynote-2016/</guid><description>&lt;p&gt;It&amp;rsquo;s the week of the largest SQL Server conference, the SQLPASS Summit. I&amp;rsquo;m in Seattle with more than 6,000 other SQL Server professionals. I made it to the Keynote this morning, only to find &lt;a href="https://twitter.com/rob_farley"&gt;Rob Farley&lt;/a&gt; sitting next to me.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got a cold and I was waiting for the DayQuil to kick in when the Keynote began. If you&amp;rsquo;ve ever met Rob, you know I was in &lt;em&gt;no danger&lt;/em&gt; of falling asleep.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/SQLSummit-Keynote-Kendra-Rob-225x300.jpg"
alt="sqlsummit-keynote-kendra-rob" width="230"&gt;
&lt;/figure&gt;
Here are my thoughts on the topics covered in today&amp;rsquo;s keynote. If you&amp;rsquo;re not at the conference, you can watch some sessions live today, plus tomorrow&amp;rsquo;s keynote, too &amp;ndash; &lt;a href="http://www.sqlpass.org/summit/2016/Live.aspx"&gt;check out PASStv&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="intelligence-in-the-database-burn-those-cpu-cores"&gt;Intelligence in the database: burn those CPU cores&lt;/h2&gt;
&lt;p&gt;We started out with an emphasis on moving application logic and intelligent prediction deeper into the database layer. The general gist seemed to be building more predictive and analytic functions into the SQL Server database itself for fast analysis and performance.&lt;/p&gt;
&lt;p&gt;For us SQL Server folks, it&amp;rsquo;s interesting and exciting to hear about SQL Server becoming even more relevant to application processing. That sounds like job security.&lt;/p&gt;
&lt;p&gt;But on the other hand, SQL Server is one of the more expensive places to do a lot of calculations because of the cost per CPU. This immediately struck me as an expensive proposition for customers.&lt;/p&gt;
&lt;h2 id="love-for-linux-demos-querying-hadoop-and-mongodb-friendly-use-of-the-word-iphone"&gt;Love for Linux, Demos Querying Hadoop and MongoDB, Friendly use of the word &amp;ldquo;iPhone&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;I was impressed by the openness to other technologies and companies shown throughout the keynote. We saw a demo of a PolyBase query that touched five different platforms, including Oracle and MongoDB. I heard the word &amp;ldquo;iPhone&amp;rdquo; and a reference to the Apple App Store from the stage without any competitiveness or growling. We saw a live demo of installing SQL Server on Linux.&lt;/p&gt;
&lt;p&gt;Microsoft has really changed their tone these days. It&amp;rsquo;s exciting.&lt;/p&gt;
&lt;h2 id="cloud-lots-of-stories-of-cool-stuff-in-cloud"&gt;Cloud, lots of stories of cool stuff in cloud&lt;/h2&gt;
&lt;p&gt;In previous years, lots of discussion of cloud technology has felt a bit heavy handed. Not everyone was ready for it. This year, it feels different.&lt;/p&gt;
&lt;p&gt;Microsoft brought customers to the stage who have been using cloud services to scale up airline pricing, game interaction (complete with &amp;ldquo;zombie matching&amp;rdquo;, and data analysis. Some of the speakers were analysts and engineers. This made it easier to relate to the theme of the day, of cloud + data + intelligence.&lt;/p&gt;
&lt;p&gt;In chatting with attendees this week as well, lots of people are talking about projects that are doing, or are planning to do, which involve the cloud. The mood at the PASS Summit is definitely shifting to be more open and exciting.&lt;/p&gt;
&lt;h2 id="on-prem-gets-some-love-too"&gt;On-prem gets some love, too&lt;/h2&gt;
&lt;p&gt;It wasn&amp;rsquo;t all cloud in the Keynote this morning. And it&amp;rsquo;s not all cloud in the sessions, either. One of the sessions that I&amp;rsquo;m excited to attend today is from Microsoft Program Manager Kevin Farlee, &amp;ldquo;Operational Analytics in SQL Server 2016 and Azure SQL Database.&amp;rdquo; I like this new world where we can talk about on-prem SQL Server, and cloud, too. Sometimes we can have both.&lt;/p&gt;
&lt;p&gt;And now, on to the learning!&lt;/p&gt;</description></item><item><title>Wildcard vs Regular Expressions - Lucene Query in Azure Search</title><link>https://kendralittle.com/2016/10/25/wildcard-vs-regular-expressions-lucene-query-in-azure-search/</link><pubDate>Tue, 25 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/25/wildcard-vs-regular-expressions-lucene-query-in-azure-search/</guid><description>&lt;p&gt;Sometimes clever developers let you try out cloud services with very little work on your part. This is one of those times - get ready for &amp;ldquo;Playing with Azure Search: No Installation Required.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I recently saw &lt;a href="https://twitter.com/mcflyamorim/status/788822126128234496"&gt;a question about Azure Search on Twitter&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Guys, is Azure Search capable to do a substring search, i.e. like &amp;lsquo;%bian%&amp;rsquo; and find a record with a &amp;lsquo;Fabiano&amp;rsquo; string in it? #sqlhelp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="thats-a-great-question"&gt;That&amp;rsquo;s a great question&lt;/h2&gt;
&lt;p&gt;I was immediately curious about the answer &amp;ndash; and I immediately wanted the answer to be &amp;lsquo;yes&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Someone else quickly responded to the tweet and explained that Azure Search does support wildcard searches, but it&amp;rsquo;s only for prefix searches. So if you&amp;rsquo;re looking for jobs that contain the word &amp;lsquo;Architect&amp;rsquo;, your query could say: show me all job titles where there&amp;rsquo;s a word leading in Arc*.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s true, but wildcard searches aren&amp;rsquo;t the only way to look for strings.&lt;/p&gt;
&lt;h2 id="i-suspected-azure-search-is-more-flexiblethan-fulltext-search"&gt;I suspected Azure Search is more flexible than Fulltext Search&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Foo-Finders-300x300.png"
alt="foo-finders" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I wanted to be able to find all architect jobs using something like &amp;lsquo;%rchit%&amp;rsquo; as well, because there&amp;rsquo;s not a lot of great ways to do this in SQL Server.&lt;/p&gt;
&lt;p&gt;In SQL Server, you can use a traditional B-Tree index to seek, but only based on the letters at the beginning of a character column.  If I want to know every business title that contains &amp;lsquo;%rchit%&amp;rsquo;, I&amp;rsquo;m going to have to scan an entire index.&lt;/p&gt;
&lt;p&gt;SQL Server fulltext indexes don&amp;rsquo;t solve the double-wildcard problem, either. Fulltext indexes support word prefix searches&amp;ndash; so a fulltext index would be great at finding all job titles that contain a word that starts with &amp;lsquo;Arch%&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;Sometimes that&amp;rsquo;s enough. But a lot of times, you do need to find a substring anywhere in a word. And sometimes you do want to offload that from your database.&lt;/p&gt;
&lt;h2 id="azure-search-supports-regular-expressions"&gt;Azure Search supports regular expressions&lt;/h2&gt;
&lt;p&gt;I did some quick searching and found a very helpful article from Microsoft&amp;rsquo;s Liam Cavanagh, &lt;a href="https://azure.microsoft.com/en-us/documentation/articles/search-query-lucene-examples/"&gt;Lucene query syntax examples for building queries in Azure Search&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s all sorts of cool stuff in the article. The examples are a hoot, because you can click on them to play with them in a browser.&lt;/p&gt;
&lt;p&gt;You can also modify the examples and see what you can get to work!&lt;/p&gt;
&lt;p&gt;Example 8 in the article is for regular expressions. It includes an example query to return all job titles that contain Senior or Junior by plugging in the regular expression, business_title:/(Sen|Jun)ior/&lt;strong&gt;)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I had one little issue because of the extra end parentheses that I highlighted in red. As soon as I tweaked the example to the following, it worked great in my browser.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/* Code example from Lucene query examples, last right paren removed */
http://fiddle.jshell.net/liamca/gkvfLe6s/1/?index=nycjobs&amp;amp;apikey=252044BE3886FE4A8E3BAA4F595114BB&amp;amp;query=api-version=2015-02-28-Preview%26queryType=full%26$select=business_title%26search=business_title:/(Sen|Jun)ior/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;rsquo;s what the results look like in Chrome:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Regular-Expression-Azure-Search-Lucene-Senior-Junior.jpg"&gt;
&lt;/figure&gt;
&lt;h2 id="but-can-we-go-full-wildcard"&gt;But can we go full wildcard?&lt;/h2&gt;
&lt;p&gt;Now that I got the example working, can I see all the job titles that contain %rchit% using the regular expression search?&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t use regular expressions a lot, but when I do I just cheat and &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html"&gt;look up syntax on the internet&lt;/a&gt;.  There may well be a better way to do this, I looked for the first thing that world.&lt;/p&gt;
&lt;p&gt;Behold:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;http://fiddle.jshell.net/liamca/gkvfLe6s/1/?index=nycjobs&amp;amp;apikey=252044BE3886FE4A8E3BAA4F595114BB&amp;amp;query=api-version=2015-02-28-Preview%26queryType=full%26$select=business_title%26search=business_title:/(.*)rchit(.*)/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The results:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Regular-Expression-Azure-Search-Lucene-contains-rchit.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;m no Architect, but that looks like it worked to me. Awesome!&lt;/p&gt;
&lt;h2 id="im-gonna-guess-that-this-can-be-slow-too"&gt;I&amp;rsquo;m gonna guess that this can be slow, too&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s probably a good reason that wildcard searches make it simple to look for words by prefix, and you have to dig around in regex to get a substring: performance. I&amp;rsquo;m just guessing here, but we&amp;rsquo;re &lt;em&gt;probably&lt;/em&gt; doing something similar to scanning an index in Azure Search (if that&amp;rsquo;s not exactly what we&amp;rsquo;re doing).&lt;/p&gt;
&lt;p&gt;But having a supported way to do this in Azure Search is still awesome&amp;ndash; it has different scale and licensing costs than doing the scanning in SQL Server. It&amp;rsquo;s all about having options.&lt;/p&gt;
&lt;h2 id="this-is-fun---play-with-it"&gt;This is fun - play with it&lt;/h2&gt;
&lt;p&gt;Even if you&amp;rsquo;re not going into the cloud tomorrow, this is really easy and fun to play around with. Grab one of those URLs and enjoy searching.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re already an Azure Search user, I&amp;rsquo;d love to hear about your experience in the comments!&lt;/p&gt;</description></item><item><title>Where do You Get Your Creativity? (Dear SQL DBA Episode 20)</title><link>https://kendralittle.com/2016/10/20/where-do-you-get-your-creativity-dear-sql-dba-episode-20/</link><pubDate>Thu, 20 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/20/where-do-you-get-your-creativity-dear-sql-dba-episode-20/</guid><description>&lt;p&gt;As a database administrator or developer, you&amp;rsquo;ll get into trouble fast if you try to force all your code and processes into a database shaped hole. You have to be creative when you problem solve  &amp;ndash; and when you communicate! So how do you cultivate creativity?&lt;/p&gt;
&lt;p&gt;You can watch the 23 minute video, &lt;a href="https://kendralittle.com/dearsqldba/"&gt;subscribe to the podcast&lt;/a&gt;, or scroll down and read the article.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/y0_q6rMqY6U?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;Where do you get your creativity from? I love your training sessions (first saw you in online training videos offered by my company) and I now read your blog, but what I love most here is your art!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/creativity-post-its-300x300.jpg"
alt="creativity-post-its" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Aww, thank you for the kind words!&lt;/p&gt;
&lt;p&gt;This question meant a lot to me, because for years I only rarely devoted much time to purposefully being creative. And that was a mistake.&lt;/p&gt;
&lt;h2 id="the-first-step-is-encouragingyourself-to-be-creative-even-when-you-meet-resistance"&gt;The first step is encouraging yourself to be creative&amp;ndash; even when you meet resistance&lt;/h2&gt;
&lt;p&gt;I went to a very small college - my graduating class was something like 13 students. A pretty high percentage of the people I studied with have become educators of different types.&lt;/p&gt;
&lt;p&gt;Recently, one of my friends remarked that a group of Chemistry students she taught responded particularly well when she used cat drawings to go along with the lessons. They got more engaged with the class and wrote that the drawings helped them remember some fairly dry material.&lt;/p&gt;
&lt;p&gt;And that got me thinking. Over the years, I&amp;rsquo;ve gotten two complaints about using my drawings in teaching SQL Server concepts &amp;ndash; they basically felt my drawings were unnecessary and made the course seem childish.&lt;/p&gt;
&lt;p&gt;I remember those criticisms very specifically. I know exactly which courses they were about, and how they were submitted. I&amp;rsquo;ve felt a lot of self-doubt over them.&lt;/p&gt;
&lt;p&gt;What I tend to forget are the far greater number of verbal and written comments that I&amp;rsquo;ve gotten saying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My drawings made the session more fun and made it easier to pay attention&lt;/li&gt;
&lt;li&gt;My poster really helped connect ideas&lt;/li&gt;
&lt;li&gt;Creativity was what made my session stand out to them, and specifically was what they valued&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of people were essentially telling me that creativity should be my personal &amp;ldquo;brand&amp;rdquo;, but I let two criticisms feel &amp;ldquo;louder&amp;rdquo; than the much greater volume of positive messages when it came to my drawings.&lt;/p&gt;
&lt;h2 id="many-of-us-feel-more-vulnerable-to-criticism-about-creativity"&gt;Many of us feel more vulnerable to criticism about creativity&lt;/h2&gt;
&lt;p&gt;To be clear, I&amp;rsquo;ve gotten plenty of criticism about other aspects to my presentations&amp;ndash; technical content, teaching mechanics, clarity, etc. I don&amp;rsquo;t remember all the details of those negative comments because I didn&amp;rsquo;t take that criticism quite as personally. It was easier for me to learn from the comment, make adjustments, and get better (which is the whole point of criticism).&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Beginner-DBA-300x294.jpg"
alt="beginner-dba" width="230"&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;I was just too vulnerable for a while when it came to my drawings. It&amp;rsquo;s a very personal area for a lot of us.&lt;/p&gt;
&lt;p&gt;Be aware that the biggest friction may come from within when it comes to creativity. The main reason I&amp;rsquo;ve seen that people don&amp;rsquo;t draw is that they tell themselves that they &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; draw. What that really means is that they can&amp;rsquo;t accept and enjoy the imperfections that they see in their drawings.&lt;/p&gt;
&lt;p&gt;If you want to be more creative, you&amp;rsquo;ve got to get past your own &amp;ldquo;I can&amp;rsquo;t&amp;rdquo; voice &amp;ndash; whether it&amp;rsquo;s drawing or problem solving.&lt;/p&gt;
&lt;h2 id="where-does-creativity-help-with-database-work"&gt;Where does creativity help with database work?&lt;/h2&gt;
&lt;p&gt;Database developers and administrators do a lot of problem solving. Creativity is huge when it comes to solving problems for data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Should the code go in the database, or somewhere else?&lt;/li&gt;
&lt;li&gt;How can we make the code as fast as possible if it is in the database?&lt;/li&gt;
&lt;li&gt;What&amp;rsquo;s the best way to set up monitoring and automation to make data management easier and more reliable?&lt;/li&gt;
&lt;li&gt;What processes are the most efficient between teams and work for everyone?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Communication is a bigger part of the DBA job than most people realize when they go into it. Creativity can also come into play when getting communication and processes to work.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When and where is the most effective time to make a suggestion?&lt;/li&gt;
&lt;li&gt;How can you develop partnerships with people in other teams to make things easier? Who might be the best people to partner with, and how can you make each others&amp;rsquo; jobs easier?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you regularly think of new ways to approach people and business problems, you&amp;rsquo;ll have an easier time as a DBA.&lt;/p&gt;
&lt;p&gt;If you just try hitting the same nail with the same hammer, you&amp;rsquo;ll end up frustrated and with some bruises.&lt;/p&gt;
&lt;h2 id="habit-to-encourage-creativity---daily-exercise"&gt;Habit to encourage creativity - daily exercise&lt;/h2&gt;
&lt;p&gt;For me, creativity and stress are polar opposites. The more stressed I am, the less creative I am. And vice versa.&lt;/p&gt;
&lt;p&gt;If I sit down and say, &amp;ldquo;I&amp;rsquo;m going to be creative&amp;rdquo; when I&amp;rsquo;m stressed, it doesn&amp;rsquo;t work. Worries just rotate through my head.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s one big thing that helps me: &lt;em&gt;exercise&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Seriously, physical exercise. Of your body. Not your brain. Sounds weird, but it really works for me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exercise alleviates the biggest obstacle to creativity - it reduces stress&lt;/li&gt;
&lt;li&gt;Exercise is a great way to &amp;ldquo;free up&amp;rdquo; my mind from what I ordinarily think about - because I focus on what I&amp;rsquo;m doing. For whatever reason, this seems to help new ideas appear for me, and allows me to get a different perspective on a situation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For me, it doesn&amp;rsquo;t have to be a specific form of exercise. I love to walk each day, and walking is hugely beneficial for my creativity &amp;ndash; whether I&amp;rsquo;m going slow or fast. I often find myself jotting down notes when I get home for a walk, or suddenly thinking of a new idea within a couple of hours of working out.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Internet tradition: consult your doctor before starting a new whatever regimen. I am not a doctor and I do not play one on television.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="capture-yourtangents"&gt;Capture your tangents&lt;/h2&gt;
&lt;p&gt;Very often, my best ideas, presentations, and drawings come from tangents. I&amp;rsquo;ll be working on Problem X when I discover Tangent Y. And Tangent Y ends up being far more compelling.&lt;/p&gt;
&lt;p&gt;Sometimes I work the tangent into my current project.&lt;/p&gt;
&lt;p&gt;Sometimes I make notes and remind myself to build it into its own project.&lt;/p&gt;
&lt;p&gt;The key is to &lt;em&gt;write down those tangents&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;These days I like to keep a mess of ideas and lists in Google Keep, because it&amp;rsquo;s free and I use an Android phone. Any kind of list works, from a simple text file on up. I have Keep lists for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blog post ideas&lt;/li&gt;
&lt;li&gt;Presentation ideas&lt;/li&gt;
&lt;li&gt;Drawing/poster ideas&lt;/li&gt;
&lt;li&gt;Tool ideas&lt;/li&gt;
&lt;li&gt;Whatever ideas (basically unclassified)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I sometimes make a mess of post it notes on my desk and herd them into a legit list later. Whatever works for you in the moment is what works!&lt;/p&gt;
&lt;h2 id="listening-to-others---ask-how-they-solve-problems"&gt;Listening to others - ask how they solve problems&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/freshing-polished-ideas-300x300.png"
alt="freshing-polished-ideas" width="230"&gt;
&lt;/figure&gt;
I love hearing about how other people solve problems.&lt;/p&gt;
&lt;p&gt;The SQLPASS conference is next week. When you meet new people at a conference, one of the ways to break the ice is to ask them simple questions about themselves. (Yeah, I&amp;rsquo;m socially awkward enough that I remind myself of things like this.)&lt;/p&gt;
&lt;p&gt;Instead of asking, &amp;ldquo;What do you do?&amp;rdquo;, you may get a more interesting answer if you ask, &amp;ldquo;What kind of problems do you get to solve?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Because software developers and database folks get to solve all sorts of cool problems! That&amp;rsquo;s what a bunch of the sessions are, as well.&lt;/p&gt;
&lt;p&gt;I think of my creative brain as being kind of like a rock tumbler. The more information you can take in from others about solving problems, the more &amp;lsquo;grit&amp;rsquo; you have in your rock tumbler to smooth out problems.&lt;/p&gt;
&lt;h2 id="what-helps-you-be-creative"&gt;What helps you be creative?&lt;/h2&gt;
&lt;p&gt;Got a secret? Even if it&amp;rsquo;s not one simple trick, I&amp;rsquo;d love to hear about it in the comments.&lt;/p&gt;</description></item><item><title>Decoding Key and Page WaitResource for Deadlocks and Blocking</title><link>https://kendralittle.com/2016/10/17/decoding-key-and-page-waitresource-for-deadlocks-and-blocking/</link><pubDate>Mon, 17 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/17/decoding-key-and-page-waitresource-for-deadlocks-and-blocking/</guid><description>&lt;p&gt;If you use SQL Server&amp;rsquo;s blocked process report or collect deadlock graphs, occasionally you&amp;rsquo;ll come across things that look like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;waitresource=&amp;ldquo;PAGE: 6:3:70133 &amp;quot;
waitresource=&amp;ldquo;KEY: 6:72057594041991168 (ce52f92a058c)&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sometimes there&amp;rsquo;s more information in the massive monster of XML that you&amp;rsquo;re scanning through (deadlock graphs have a resource list that help reveal the object and index name), but sometimes there isn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a reference on how to decode them.&lt;/p&gt;
&lt;p&gt;All of this information is out there on the internet already in various places, it&amp;rsquo;s just spread out! I&amp;rsquo;m going to pull the whole thing together, from DBCC PAGE to hobt_id to the undocumented %%physloc%% and %%lockres%% functions.&lt;/p&gt;
&lt;p&gt;First we&amp;rsquo;ll talk through PAGE lock waits, then we&amp;rsquo;ll hit the KEY lock waits.&lt;/p&gt;
&lt;h2 id="page-lock-waits"&gt;Page lock waits&lt;/h2&gt;
&lt;h3 id="example-1-waitresourcepage-6370133--database_id--fileid--pagenumber"&gt;Example 1: waitresource=&amp;ldquo;PAGE: 6:3:70133 &amp;quot; = Database_Id : FileId : PageNumber&lt;/h3&gt;
&lt;p&gt;If your query was waiting on a page level lock, SQL Server gives you the page address.&lt;/p&gt;
&lt;p&gt;Breaking &amp;ldquo;PAGE: 6:3:70133&amp;rdquo; down, we&amp;rsquo;ve got:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;database_id=6&lt;/li&gt;
&lt;li&gt;data_file_id = 3&lt;/li&gt;
&lt;li&gt;page_number = 70133&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="11-decode-the-database_id"&gt;1.1) Decode the database_id&lt;/h4&gt;
&lt;p&gt;Find the database name with this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s the &lt;a href="https://kendralittle.com/2016/09/13/deadlock-code-for-the-wideworldimporters-sample-database/"&gt;WideWorldImporters sample database&lt;/a&gt; on my SQL Server instance.&lt;/p&gt;
&lt;h4 id="12-look-up-the-data-file-name--if-youre-interested"&gt;1.2) Look up the data file name &amp;ndash; if you&amp;rsquo;re interested&lt;/h4&gt;
&lt;p&gt;We&amp;rsquo;re going to use the data file id in the next step to find the name of the table. You can just move on. But if you&amp;rsquo;re curious about the name of the data file, you can look it up by using the database and plugging the data file id into this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;physical_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;database_files&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In WideWorldImporters, this is the data file named WWI_UserData, and I restored it to C:\MSSQL\DATA\WideWorldImporters_UserData.ndf. (Whoops, you caught me putting files on my system drive.).&lt;/p&gt;
&lt;h4 id="13-get-the-name-of-the-object-from-dbcc-page"&gt;1.3) Get the name of the object from DBCC PAGE&lt;/h4&gt;
&lt;p&gt;We know this is page # 70133 in data file 3 in the WideWorldImporters database. We can look at that page with the undocumented DBCC PAGE and Trace Flag 3604.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: I prefer running DBCC page against a restored backup elsewhere, because it's not supported. In some cases, &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/776144/dbcc-page-incorrect-output-with-filtered-indexes"&gt;running DBCC PAGE can cause stack dumps&lt;/a&gt;.
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This trace flag makes DBCC PAGE output go to our Messages tab
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;instead of the SQL Server Error Log file */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* DBCC PAGE (DatabaseName, FileNumber, PageNumber, DumpStyle)*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WideWorldImporters&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;70133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Scrolling down in the output, I can find the object_id and IndexId:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/DBCC-PAGE-WaitResource.jpg"
alt="dbcc-page-waitresource"&gt;
&lt;/figure&gt;
&lt;p&gt;Whew, almost there!&lt;/p&gt;
&lt;p&gt;I can now find the table and index name with this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;94623380&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And behold, this lock wait was on the PK_Sales_OrderLines index on the Sales.OrderLines table.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: In SQL Server 2014 and higher, you could also find the object name using the undocumented sys.dm_db_database_page_allocations dynamic management object. But you have to query all the  pages in the database, which seems not as awesome against large databases &amp;ndash; so I listed the DBCC page method.&lt;/p&gt;
&lt;h4 id="14-can-i-see-the-data-on-thepage-that-was-locked"&gt;1.4) Can I see the data on the page that was locked?&lt;/h4&gt;
&lt;p&gt;Well, yes. But &amp;hellip; do you really need to?&lt;/p&gt;
&lt;p&gt;This is slow even on small tables. But it&amp;rsquo;s kinda fun, so&amp;hellip; since you read this far&amp;hellip; let&amp;rsquo;s talk about %%physloc%%!&lt;/p&gt;
&lt;p&gt;%%physloc%% is an undocumented piece of magic that will return the physical record locator for every row. You can  &lt;a href="http://www.sqlskills.com/blogs/paul/sql-server-2008-new-undocumented-physical-row-locator-function/"&gt;use %%physloc%% with sys.fn_PhysLocFormatter in SQL Server 2008&lt;/a&gt; and higher.&lt;/p&gt;
&lt;p&gt;Now that we know that the page lock wait was on Sales.OrderLines, we can see all the data in that table on data file = 3 and page number = 70133 with this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_PhysLocFormatter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;physloc&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderLines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_PhysLocFormatter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;physloc&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(3:70133%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Like I said, this is slow even on tiny tables.&lt;/em&gt; I&amp;rsquo;ve added NOLOCK to the query because while we want a glance at this info, we have no guarantee that it&amp;rsquo;s the way it was earlier when the blocking happened anyway&amp;ndash; we&amp;rsquo;re guessing, so we may as well do dirty reads.&lt;/p&gt;
&lt;p&gt;But woo hoo, it gives me a clean display of the 25 rows which the query was fighting for:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/physloc-data-on-page-with-resourcewait.jpg"
alt="physloc-data-on-page-with-resourcewait"&gt;
&lt;/figure&gt;
&lt;p&gt;That&amp;rsquo;s enough detail on waitresource=PAGE. What if you were waiting on a KEY?&lt;/p&gt;
&lt;h2 id="key-lock-waits"&gt;Key lock waits&lt;/h2&gt;
&lt;h3 id="example-2-waitresourcekey-672057594041991168-ce52f92a058c--database_id-hobt_id--magic-hash-that-you-can-decode-with-lockres-if-you-really-want"&gt;Example 2: waitresource=&amp;ldquo;KEY: 6:72057594041991168 (ce52f92a058c)&amp;rdquo; = Database_Id, HOBT_Id ( Magic hash that you can decode with %%lockres%% if you really want)&lt;/h3&gt;
&lt;p&gt;If your query was trying to lock a row in an an index and was blocked, you get a totally different style of address.&lt;/p&gt;
&lt;p&gt;Breaking &amp;ldquo;6:72057594041991168 (ce52f92a058c)&amp;rdquo; down, we&amp;rsquo;ve got:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;database_id = 6&lt;/li&gt;
&lt;li&gt;hobt_id = 72057594041991168&lt;/li&gt;
&lt;li&gt;magic hash value = (ce52f92a058c)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="21-decode-the-database_id"&gt;2.1) Decode the database_id&lt;/h4&gt;
&lt;p&gt;This works the exact same way it did for the page example above! Find the database name with this query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;database_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my case, that&amp;rsquo;s still the &lt;a href="https://kendralittle.com/2016/09/13/deadlock-code-for-the-wideworldimporters-sample-database/"&gt;WideWorldImporters sample database&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="22-decode-the-hobt_id"&gt;2.2) Decode the hobt_id&lt;/h4&gt;
&lt;p&gt;We need to use that database, and then query sys.partitions, with some helper joins to figure out the table and index name&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partitions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hobt_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;72057594041991168&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That tells me that the query was waiting for a lock on Application.Countries, using the PK_Application_Countries index.&lt;/p&gt;
&lt;h4 id="23-now-for-some-lockres-magic---if-you-want-to-figure-out-which-row-was-locked"&gt;2.3) Now for some %%lockres%% magic - if you want to figure out which row was locked&lt;/h4&gt;
&lt;p&gt;If I really want to know exactly which row the lock needed, I can decode that by querying the table itself. We can use the undocumented %%lockres%% function to find the row equal to that magic hash value.&lt;/p&gt;
&lt;p&gt;Note that this is going to scan the table, and on large tables that might not be so awesome all the time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Countries&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;lockres&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(ce52f92a058c)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I added NOLOCK to this query (&lt;a href="https://twitter.com/Aschenbrenner/status/788036874891853824"&gt;as Klaus Aschenbrenner suggested on Twitter&lt;/a&gt;) because locking can be an issue &amp;ndash; and in this case, you&amp;rsquo;re looking to get a glance at the data as it is now, not as it was earlier when the transaction ran&amp;ndash; so I don&amp;rsquo;t think data consistency is a big issue.&lt;/p&gt;
&lt;p&gt;Voila, the row we were fighting for appears!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/LockRes-SQLServer-WaitResource-Key.jpg"
alt="lockres-sqlserver-waitresource-key"&gt;
&lt;/figure&gt;
&lt;h2 id="credits-and-more-reading"&gt;Credits and more reading&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not sure who first documented many of these things, but here are two posts on some of the less documented nitty gritty that you may enjoy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Paul Randal&amp;rsquo;s post on &lt;a href="http://www.sqlskills.com/blogs/paul/sql-server-2008-new-undocumented-physical-row-locator-function/"&gt;%%physloc%% and sys.fn_PhysLocFormatter&lt;/a&gt; (how we saw the data on the page lock wait example)&lt;/li&gt;
&lt;li&gt;This StackOverflow question on &lt;a href="http://dba.stackexchange.com/questions/106762/how-can-i-convert-a-key-in-a-sql-server-deadlock-report-to-the-value"&gt;using %%lockres%%&lt;/a&gt;  (how we found the row on the row lock wait example). One of the answers links to &lt;a href="http://www.scarydba.com/2010/03/18/undocumented-virtual-column-lockres/"&gt;Grant Fritchey writing about %%lockres%% back in 2010&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Should You Rebuild or Reorganize Indexes on Large Tables? (Dear SQL DBA Episode 19)</title><link>https://kendralittle.com/2016/10/13/should-you-rebuild-or-reorganize-indexes-on-large-tables-dear-sql-dba-episode-19/</link><pubDate>Thu, 13 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/13/should-you-rebuild-or-reorganize-indexes-on-large-tables-dear-sql-dba-episode-19/</guid><description>&lt;p&gt;The bigger your indexes are, the harder your index maintenance falls. Is it better to rebuild big indexes? Or should you reorganize?&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re short on time, scroll down: an article with all the content is below the 23 minute video.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/fu6DGsDYnKI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s this week&amp;rsquo;s question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;Any advice for rebuilding indexes on very large tables? We’ve got a large table with over 2 billion rows. Index rebuilds consume over 300GB of transaction log space even though we&amp;rsquo;re backing up the log every 3 minutes.&lt;/p&gt;
&lt;p&gt;To solve this problem, should we reorganize instead of rebuild?&lt;/p&gt;
&lt;p&gt;Any issues with never rebuilding indexes – just reorganizing them?&lt;/p&gt;
&lt;p&gt;We are using SQL Server 2014 Enterprise Edition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="rebuilding-big-indexes-can-cause-big-headaches"&gt;Rebuilding big indexes can cause big headaches&lt;/h2&gt;
&lt;p&gt;Index rebuilds have a log lot going for them, but they also have some drawbacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ALTER INDEX REBUILD&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center"&gt;Pros&lt;/th&gt;
&lt;th style="text-align: center"&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Can use parallelism - which can reduce the runtime (Enterprise Edition)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Single threaded only in Standard Edition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;ONLINE option (Enterprise Edition) Note: this requires an exclusive lock on the table at the end of the operation.&lt;/td&gt;
&lt;td style="text-align: center"&gt;When performed offline, the entire table is unavailable for the duration of the operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Defragments all levels of the index - leaf and intermediate pages&lt;/td&gt;
&lt;td style="text-align: center"&gt;Rollbacks can be long and excruciating when rebuild fails or is cancelled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Also updates statistics on the table with a FULLSCAN of all the data&lt;/td&gt;
&lt;td style="text-align: center"&gt; Causes queries to generate new execution plans when they run again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Reapplies options such as fillfactor and compression, and gives you the option to change those settings.&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Minimal logging is available under some recovery models&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="rebuilding-giant-indexes-with-availability-groups-or-database-mirroring-is-particularly-tricky"&gt;Rebuilding giant indexes with Availability Groups or Database Mirroring is particularly tricky&lt;/h3&gt;
&lt;p&gt;With very large indexes, rebuilds take longer, generate more log, impact performance more while they&amp;rsquo;re running.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using high availability features like Availability Groups or database mirroring that stream the log between replicas, generating a lot of log data very quickly can create problems.&lt;/p&gt;
&lt;p&gt;Your replica/ mirrors may fall behind. Depending on the latency between replicas, the size of the indexes rebuilt, and other operations in the database, they may be out of your Recovery Point Objective / Recovery Time objective for a long time.&lt;/p&gt;
&lt;p&gt;In this situation, it&amp;rsquo;s particularly attractive to drip changes into the log more slowly. One of the ways to do this is to use REORGANIZE for those large indexes.&lt;/p&gt;
&lt;h3 id="youre-right-to-consider-reorganizing"&gt;You&amp;rsquo;re right to consider reorganizing!&lt;/h3&gt;
&lt;p&gt;Of course, things aren&amp;rsquo;t &lt;em&gt;perfect&lt;/em&gt; when it comes to REORGANIZE. It has some downsides as well.&lt;/p&gt;
&lt;p&gt;ALTER INDEX REORGANIZE&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center"&gt;Pros&lt;/th&gt;
&lt;th style="text-align: center"&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt; Tends to &amp;ldquo;trickle&amp;rdquo; changes into the log more slowly (a pro only for specific situations)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Single threaded only - regardless of edition &amp;ndash; so it&amp;rsquo;s slower.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Fully online in every edition&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;If cancelled or killed, it just stops where it is &amp;ndash; no giant rollback.&lt;/td&gt;
&lt;td style="text-align: center"&gt;Defragments only the leaf level of the index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Does not cause plan recompilation&lt;/td&gt;
&lt;td style="text-align: center"&gt;Does not update statistics - you have to manage that yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Honors/reapplies existing settings such as fillfactor and compression&lt;/td&gt;
&lt;td style="text-align: center"&gt;Does not allow you to change settings such as fillfactor and compression&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;When it comes to giant indexes, the biggest downsides are related to the whole reason you&amp;rsquo;d use it in the first place: it&amp;rsquo;s slow!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;That single thread goes slow and steady through the leaf of your index, and it can easily take up your whole maintenance window&lt;/li&gt;
&lt;li&gt;While you can cancel the command and it stops without a giant rollback, there&amp;rsquo;s no built in way to programmatically run it against an index for a specific time. It&amp;rsquo;s cancel or kill.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="you-may-need-to-exclude-the-largest-indexes-from-automated-rebuilds-and-handle-them-manually"&gt;You may need to exclude the largest indexes from automated rebuilds and handle them manually&lt;/h3&gt;
&lt;p&gt;In cases where REBUILDs on large indexes can&amp;rsquo;t happen because they put replicas too far behind or cause too heavy of a performance impact, typically these large indexes are manually REORGANIZED in spurts while a DBA team member is around to babysit.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a bit like watching paint dry.&lt;/p&gt;
&lt;p&gt;Going through this experience of babysitting large index reorganizes generally causes DBAs to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start researching ways to speed up communication between their replicas and storage under their transaction logs.&lt;/li&gt;
&lt;li&gt;Become more moderate on the amount of fragmentation they allow indexes. It may be fine to reorganize small indexes that are 5% fragmented or more and rebuild when they&amp;rsquo;re 30% or more, but these thresholds just don&amp;rsquo;t work for giant indexes when you have a small maintenance window or sensitive replicas/mirrors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="minimal-logging-is-available-for-rebuild--but-you-may-not-be-able-to-use-the-recovery-model-required"&gt;Minimal logging is available for REBUILD - but you may not be able to use the recovery model required&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s worth talking about the &amp;ldquo;minimal logging&amp;rdquo; pro for rebuilds. If you don&amp;rsquo;t need point in time recovery and can lose any changes that occur between full backups and are in the SIMPLE recovery model, you benefit from this all the time.&lt;/p&gt;
&lt;p&gt;If you need to limit data loss and are in the FULL recovery model, you may still have to switch to SIMPLE during some outages for large data changes. And during those outages, you might want to fit in some offline index rebuilds if you have the time, because they can be faster.&lt;/p&gt;
&lt;p&gt;In the SIMPLE and BULK LOGGED recovery models, ALTER INDEX REBUILD doesn&amp;rsquo;t have to log every row. There&amp;rsquo;s a few caveats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This doesn&amp;rsquo;t help you if you&amp;rsquo;re using an AG or Mirroring&amp;ndash; FULL recovery model required&lt;/li&gt;
&lt;li&gt;Under BULK LOGGED, you&amp;rsquo;ll still have large transaction log &lt;em&gt;backups&lt;/em&gt; after a large rebuild, they just pull from the data files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The amount logged under BULK LOGGED and SIMPLE varies depending on whether you&amp;rsquo;re doing ONLINE or OFFLINE rebuilds. Kalen Delaney has test code and sample numbers in her post, &amp;ldquo;&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2011/03/08/what-gets-logged-for-index-rebuilds.aspx"&gt;What Gets Logged for Index Rebuild Operations&lt;/a&gt;?&amp;rdquo;&lt;/p&gt;
&lt;h3 id="any-issues-with-never-rebuilding-indexes--just-reorganizing-them"&gt;Any issues with never rebuilding indexes – just reorganizing them?&lt;/h3&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/alterindexrainbow-300x300.png"
alt="alterindexrainbow" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Rebuilding an index fixes up the whole structure. Picture an index as a triangle, with a root page, intermediate pages, and leaf pages. The rebuild command will defragment all those intermediate pages.&lt;/p&gt;
&lt;p&gt;Reorganizing only works on the leaf pages. It doesn&amp;rsquo;t work on the intermediate pages between the root and the leaf.&lt;/p&gt;
&lt;p&gt;Larger indexes have more intermediate levels and pages. These pages can get empty space on them and become out of order over time as well.&lt;/p&gt;
&lt;p&gt;Fragmentation in intermediate pages isn&amp;rsquo;t usually a problem at all &amp;ndash; one of the more common confusions of new DBAs looking at fragmentation is that they see that intermediate pages in small indexes are fragmented immediately after a rebuild, no matter what they do. That&amp;rsquo;s actually normal.&lt;/p&gt;
&lt;p&gt;If you never ever rebuild a large index, you could potentially lose some performance due to massive fragmentation in the intermediate level of the indexes&amp;ndash; but I think it&amp;rsquo;d likely be more a difference of microseconds than milliseconds per query.&lt;/p&gt;
&lt;p&gt;If it were me, I&amp;rsquo;d generally consider rebuilding problem &amp;ldquo;giant&amp;rdquo; index during outage/maintenance windows every six months or a year. But it&amp;rsquo;s my inner paranoid, tinfoil hat wearing DBA saying that.&lt;/p&gt;
&lt;p&gt;But hey, in some systems microseconds do matter! In that case, breaking up these giant indexes into partitions is probably desirable (more on that soon).&lt;/p&gt;
&lt;h2 id="tips"&gt;Tips&lt;/h2&gt;
&lt;h3 id="dont-rebuild-all-on-large-tables"&gt;Don&amp;rsquo;t REBUILD ALL on large tables&lt;/h3&gt;
&lt;p&gt;SQL Server allows you to run ALTER INDEX ALL REBUILD, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REBUILD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The syntax is convenient, but &lt;a href="https://technet.microsoft.com/en-us/library/ms189858.aspx"&gt;as Books Online explains&lt;/a&gt;, &amp;ldquo;When ALL is specified, all indexes on the table are dropped and rebuilt in a single transaction.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The bigger the transaction, the worse the rollback can be. You definitely want to handle the indexes individually.&lt;/p&gt;
&lt;h3 id="consider-waiting-between-operations"&gt;Consider waiting between operations&lt;/h3&gt;
&lt;p&gt;This is a little counter-intuitive when you have a short maintenance window, but it can ease some pains.&lt;/p&gt;
&lt;p&gt;Adding a &amp;ldquo;waiting&amp;rdquo;  period between index commands can reduce impact on the instance and Availability Group replicas or Database Mirrors. Many popular index maintenance scripts have an option for this.&lt;/p&gt;
&lt;h3 id="long-term-table-partitioning-can-break-up-large-chunks-of-data"&gt;Long term, table partitioning can break up large chunks of data&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m not a fan of partitioning for everything &amp;ndash; I did a video earlier this year on &lt;a href="https://kendralittle.com/2016/05/03/why-table-partitioning-doesnt-speed-up-query-performance-video/"&gt;Why Table Partitioning Doesn&amp;rsquo;t Speed Up Query Performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But table partitioning can be excellent for data management. Everything we&amp;rsquo;ve talked about so far has had downsides and hasn&amp;rsquo;t really provided a deep solution for the problem&amp;ndash; partitioning isn&amp;rsquo;t easy, but long term it can really help with these problems.&lt;/p&gt;
&lt;p&gt;Two things to know:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Table partitioning is an Enterprise feature&lt;/li&gt;
&lt;li&gt;Online partition level rebuilds were added in SQL Server 2014. Prior to that you could rebuild entire partitioned indexes online, but partition level rebuilds were offline.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By breaking up the table into smaller chunks, partitioning makes it much easier to take advantage of all the strengths of rebuilds without so many downsides. It&amp;rsquo;s worth investigating if this might be an option (but be careful about query performance).&lt;/p&gt;</description></item><item><title>Books to Learn SQL Server Performance Tuning and Database Design</title><link>https://kendralittle.com/2016/10/11/books-to-learn-sql-server-performance-tuning-and-database-design/</link><pubDate>Tue, 11 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/11/books-to-learn-sql-server-performance-tuning-and-database-design/</guid><description>&lt;p&gt;I get a lot of requests about which books are helpful to learn performance tuning and database design. I totally get that &amp;ndash; I still like learning with books. It doesn&amp;rsquo;t mean training videos or blogs are any less cool. They can all work together.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Books-300x300.png"
alt="books" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;You don&amp;rsquo;t need to read all the books in each topic. Browse the book descriptions and look through the free PDFs to find the best starting place for your own goals.&lt;/p&gt;
&lt;h2 id="sql-server-query-performance-tuning-books"&gt;SQL Server Query Performance Tuning Books&lt;/h2&gt;
&lt;p&gt;Grant Fritchey has written terrific books on learning performance tuning:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.apress.com/9781430267430"&gt;SQL Server Query Performance Tuning&lt;/a&gt; (printed book only)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.simple-talk.com/books/sql-books/sql-server-execution-plans-second-edition-by-grant-fritchey/"&gt;SQL Server Execution plans&lt;/a&gt; (free PDF, or you can buy the printed book)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jonathan Kehayias and Erin Stellato wrote an e-book on wait statistics, which are critical for perf tuning a workload:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.simple-talk.com/free-stuff/sql-server-performance-tuning-using-wait-statistics-a-beginners-guide/"&gt;SQL Server Performance Tuning Using Wait Statistics: A Beginner&amp;rsquo;s Guide&lt;/a&gt; (PDF only).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Louis Davidson and Tim Ford wrote a book on using wait statistics and even more DMVs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.simple-talk.com/books/sql-books/performance-tuning-with-sql-server-dynamic-management-views/"&gt;Performance Tuning with SQL Server Dynamic Management Views&lt;/a&gt; (free PDF, or you can buy the printed book)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sql-server-database-design-books---learn-from-louis"&gt;SQL Server Database Design Books - Learn from Louis&lt;/h2&gt;
&lt;p&gt;Louis Davidson has written the book on relational database design in SQL Server. He&amp;rsquo;s written the book more than once, and it looks like he&amp;rsquo;s giving us an updated version for 2016 soon, too!&lt;/p&gt;
&lt;p&gt;As of this moment, the most recent version is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.drsql.org/Pages/ProSQLServerDatabaseDesign.aspx"&gt;SQL Server 2012 Relational Database Design and Implementation&lt;/a&gt; (printed book only)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that this includes &amp;ldquo;implementation&amp;rdquo;. Louis thinks a lot about how things work in SQL Server and takes a practical approach. His website has a lot of his presentation materials as free downloads if you&amp;rsquo;d like to get a sample of his work before buying the book.&lt;/p&gt;</description></item><item><title>Can I Use Statistics to Design Indexes? (Dear SQL DBA Episode 18)</title><link>https://kendralittle.com/2016/10/06/can-i-use-statistics-to-design-indexes-dear-sql-dba-episode-18/</link><pubDate>Thu, 06 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/06/can-i-use-statistics-to-design-indexes-dear-sql-dba-episode-18/</guid><description>&lt;p&gt;Should you look at automatically created statistics on  your tables in SQL Server to help you design better indexes? Learn why in this 20 minute video, or &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;subscribe to the Dear SQL DBA podcast&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;No time to watch?&lt;/em&gt; Scroll on down, everything is written in article form below the video.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Dv9Mtbpeqt4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s this week&amp;rsquo;s question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve noticed that many indexes in my data warehouse aren&amp;rsquo;t used frequently. Is there a way to use the automatically generated statistics to make useful indexes?&lt;/p&gt;
&lt;p&gt;&amp;hellip; (insert witty pun about indexes)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve been asked this question several times, and I even remember once wondering this myself.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s no good way to analyze the column based statistics that SQL Server automatically generates for the purpose of index design. Let&amp;rsquo;s talk about why.&lt;/p&gt;
&lt;h2 id="first-why-do-we-have-statistics-anyway"&gt;First: Why do we have &amp;lsquo;statistics&amp;rsquo;, anyway?&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say we have a table named dbo.Grades. It has columns for GradeId, ClassId, StudentId, Year, Term, and Grade.&lt;/p&gt;
&lt;p&gt;We run a query looking for all StudentIds where Year=1990.&lt;/p&gt;
&lt;p&gt;The table has a Clustered Primary Key on GradeId &amp;ndash; so the whole table is stored sorted by GradeId. That doesn&amp;rsquo;t help our query at all, we want the StudentIds where Year = 1990.&lt;/p&gt;
&lt;p&gt;The table has a nonclustered index on Year and GradeId. That nonclustered index does NOT contain StudentId, though.&lt;/p&gt;
&lt;p&gt;So SQL Server has two main options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is it better for SQL Server to go look at the nonclustered index and then loop back into the base table and look up the StudentId using the GradeId?&lt;/li&gt;
&lt;li&gt;Or it might be easier to just scan the whole dbo.Grades table and check the StudentId on each row. Maybe the school was only open for the year 1990, and all the rows have that value!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;How does SQL Server know which is better?&lt;/p&gt;
&lt;p&gt;SQL Server uses statistics to guess which way is the most efficient to execute your query.&lt;/p&gt;
&lt;h2 id="statistics-vs-indexes-and-their-relationship"&gt;Statistics vs Indexes (and their relationship)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Statistics&lt;/strong&gt; are little, tiny pieces of metadata that describe the data in the table &amp;ndash; things like an approximation of the number of rows equal to 1990. Statistics don&amp;rsquo;t take up a lot of space in the database.&lt;/p&gt;
&lt;p&gt;When you create an &lt;strong&gt;index&lt;/strong&gt;, a statistic is automatically created for the key columns in the index. This can be a multi-column statistic if you have multiple key columns, but the statistic describes the first column in the index in the most detail.&lt;/p&gt;
&lt;p&gt;If you use a predicate like Year = 1990 against a column that isn&amp;rsquo;t the leading column in an index, SQL Server will create a &lt;strong&gt;single-column statistic&lt;/strong&gt;. (Fine print: automatic stats creation can be disabled using a database setting.)&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;strong&gt;indexes&lt;/strong&gt; are COPIES of the data itself for the columns defined in the index. The index on Year and GradeId on the dbo.Grades table takes up extra space on disk and on memory and has copies of all the rows for Year and GradeId.&lt;/p&gt;
&lt;p&gt;SQL Server uses &lt;strong&gt;statistics&lt;/strong&gt; to optimize an execution plan.&lt;/p&gt;
&lt;p&gt;SQL Server uses &lt;strong&gt;indexes&lt;/strong&gt; within the execution plan to find data.&lt;/p&gt;
&lt;h2 id="what-does-the-existence-of-a-system-created-column-statistic-tell-us"&gt;What does the existence of a system created column statistic tell us?&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve talked a lot so far about how much statistics and indexes are related. This is why it seems like statistics might be useful for designing indexes!&lt;/p&gt;
&lt;p&gt;But here&amp;rsquo;s the thing &amp;ndash; SQL Server doesn&amp;rsquo;t track and report on how many times a statistic was used during optimization.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t write the optimizer, but I&amp;rsquo;m not sad about this at all, I think it&amp;rsquo;s fine, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Optimization needs to be very fast. SQL Server wants to start your query as soon as it can. Everything that has to be written out during that process costs CPU and time.&lt;/li&gt;
&lt;li&gt;Just considering a column statistic in optimization doesn&amp;rsquo;t necessarily mean that a single column index on that column would be useful. There might be a multi-column index that would be useful. Or it might actually be better for it to be scanning the table! We wouldn&amp;rsquo;t know just by the fact that the statistic had been examined by the optimizer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To have useful information about which single-column statistics might be needed in an index, SQL Server would have to do a lot of work&amp;ndash; and it&amp;rsquo;s already got a feature in optimization for this at a higher level.&lt;/p&gt;
&lt;p&gt;Whenever there&amp;rsquo;s more than one way to run a query, SQL Server thinks about whether an index would help the query run faster. If it thinks an index would help, it records this using the &amp;ldquo;Missing Indexes&amp;rdquo; feature.&lt;/p&gt;
&lt;h2 id="i-wouldnt-make-too-many-assumptions-on-a-column-that-lacks-statistics-either"&gt;I wouldn&amp;rsquo;t make too many assumptions on a column that lacks statistics, either&lt;/h2&gt;
&lt;p&gt;If a column does NOT have a statistic on it, that isn&amp;rsquo;t proof that the column is unused.&lt;/p&gt;
&lt;p&gt;Statistics are automatically created on columns where you use joins and &amp;lsquo;where&amp;rsquo; predicates.&lt;/p&gt;
&lt;p&gt;Some columns may just be returned to the user without being filtered. They wouldn&amp;rsquo;t need a statistic generated for that. But the columns are still in use&amp;ndash; and in some cases, using them as &amp;ldquo;included columns&amp;rdquo; in indexes might be useful.&lt;/p&gt;
&lt;p&gt;So I wouldn&amp;rsquo;t use the existence OR non-existence of column statistics to make decisions about indexes.&lt;/p&gt;
&lt;p&gt;And anyway, we have other options!&lt;/p&gt;
&lt;h2 id="whats-the-best-way-to-design-indexes"&gt;What&amp;rsquo;s the best way to design indexes?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s two main approaches you can take. After you&amp;rsquo;ve been doing this a while, you&amp;rsquo;ll probably mix the approaches.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Identify the most expensive queries that run in each database, and tune indexes for those&lt;/em&gt;. You can find the &amp;ldquo;most expensive&amp;rdquo; queries using any of the following tools: SQL Server Query Store, the SQL Server Execution Plan cache, or a monitoring tool that watches execution and persists data from the plan cache and memory for longer analysis (and doesn&amp;rsquo;t get cleared out by memory pressure or restarts).&lt;/li&gt;
&lt;li&gt;Use SQL Server&amp;rsquo;s &amp;ldquo;Missing index requests&amp;rdquo; to see where SQL Server is asking for an index. This isn&amp;rsquo;t perfect &amp;ndash; it has to make those requests in a hurry, and the requests get cleared out when you take the database offline (&lt;a href="https://kendralittle.com/2016/03/07/sql-server-2016-rc0-fixes-index-usage-stats-bug-missing-indexes-still-broken/"&gt;or rebuild an index on the table&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="want-to-learn-more"&gt;Want to learn more?&lt;/h2&gt;
&lt;p&gt;Check out my article &amp;ldquo;&lt;a href="https://kendralittle.com/2016/04/18/updating-statistics-in-sql-server-maintenance-answers/"&gt;Updating Statistics in SQL Server: Maintenance Questions and Answers&lt;/a&gt;,&amp;rdquo; or my article and podcast episode &amp;ldquo;&lt;a href="https://kendralittle.com/2016/08/11/teach-yourself-sql-server-performance-tuning-dear-sql-dba-episode-12/"&gt;Teach Yourself SQL Server Performance Tuning&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Last Minute Coupon Code for 2016 SQLPASS Summit</title><link>https://kendralittle.com/2016/10/05/last-minute-coupon-code-for-2016-sqlpass-summit/</link><pubDate>Wed, 05 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/05/last-minute-coupon-code-for-2016-sqlpass-summit/</guid><description>&lt;p&gt;I can&amp;rsquo;t wait to teach my full day course, &lt;a href="http://www.sqlpass.org/summit/2016/Sessions/Details.aspx?sid=47583"&gt;SQL Server Index Formulas: Problems and Solutions&lt;/a&gt; in Seattle at the PASS Summit on Tuesday, October 25th. Woot! Less than 3 weeks away!&lt;/p&gt;
&lt;h2 id="discount-code"&gt;Discount Code&lt;/h2&gt;
&lt;p&gt;If you haven&amp;rsquo;t been able to sign up yet, it&amp;rsquo;s still worth a shot to check with your boss and ask if it can work out.&lt;/p&gt;
&lt;p&gt;If having a coupon code helps your mission, the registration code &lt;strong&gt;PRE250JKL&lt;/strong&gt; will get you a full three day Summit registration with a pre-conference session for $250 off.&lt;/p&gt;
&lt;p&gt;This code expires at midnight Thursday, Oct 13. &lt;a href="http://www.sqlpass.org/summit/2016/RegisterNow.aspx"&gt;Register here&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/gys4bsT4LqI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>Track Query Tuning Progress and History in Plan Explorer</title><link>https://kendralittle.com/2016/10/04/track-query-tuning-progress-and-history-in-plan-explorer/</link><pubDate>Tue, 04 Oct 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/10/04/track-query-tuning-progress-and-history-in-plan-explorer/</guid><description>&lt;p&gt;As you tweak and test queries, it&amp;rsquo;s awfully useful to see how the performance has changed.&lt;/p&gt;
&lt;h2 id="plan-explorer-history-feature"&gt;Plan Explorer History Feature&lt;/h2&gt;
&lt;p&gt;Plan Explorer has a way to do this, and it allows you to make notes as you go. This used to be a &amp;lsquo;Pro&amp;rsquo; feature which cost money, but SQL Sentry has now made Plan Explorer free &amp;ndash; good news, y&amp;rsquo;all! This is a client tool and there is no need to change the SQL Server itself to use it.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an animated gif showing how it works:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/ULdj9tA4aDP35Miaxc/source.gif"
alt="plan-explorer-using-history-and-comments"&gt;
&lt;/figure&gt;
&lt;h2 id="saving-your-work"&gt;Saving Your Work&lt;/h2&gt;
&lt;p&gt;Don&amp;rsquo;t lose your work! To save all versions in your history with plans, notes, etc. click &amp;lsquo;File&amp;rsquo; and save, and save a whole .pesession file.&lt;/p&gt;
&lt;p&gt;And to be clear, I could have run both of these statements in one go and compared the results of both statements in a single pane. I just wanted to simulate changing the query slightly to test how it ran afterward, without having to make the viewer wait while I typed out that whole index hint.&lt;/p&gt;
&lt;h2 id="tips-and-observations"&gt;Tips and Observations&lt;/h2&gt;
&lt;p&gt;Some other observations I made:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl + E keyboard shortcut will run &amp;lsquo;Get Actual Plans&amp;rsquo;.&lt;/li&gt;
&lt;li&gt;The &amp;lsquo;A&amp;rsquo; in the type column probably stands for &amp;lsquo;Actual Plans&amp;rsquo;. If you do an estimated plan, you get an &amp;lsquo;E&amp;rsquo; there.&lt;/li&gt;
&lt;li&gt;If you don&amp;rsquo;t see the History panel by default, open it up using the &amp;lsquo;View&amp;rsquo; menu.&lt;/li&gt;
&lt;li&gt;The &amp;lsquo;Total Time&amp;rsquo; column is the same as &amp;lsquo;Duration&amp;rsquo; in the results pane. It&amp;rsquo;s handy to have it there!&lt;/li&gt;
&lt;li&gt;You can also add &amp;lsquo;Actual Rows&amp;rsquo; to the history pane if you want to see that. Right click on the headers and get the Column Chooser.&lt;/li&gt;
&lt;li&gt;You can delete items in the history panel, just right click and choose &amp;lsquo;Delete&amp;rsquo;.&lt;/li&gt;
&lt;li&gt;You can also save individual history items by right clicking and choosing &amp;lsquo;Save&amp;rsquo;.&lt;/li&gt;
&lt;li&gt;If you notice the moving lines in the query plan the second time the query runs, that&amp;rsquo;s because I left the &amp;lsquo;Live Query Profile&amp;rsquo; feature on, which is enabled by default. You can toggle that on and off under the &amp;lsquo;Get Actual Plan&amp;rsquo; button (hit the arrow to the right).&lt;/li&gt;
&lt;li&gt;I haven&amp;rsquo;t notice a measurable difference in duration when running queries with &amp;lsquo;Live Query Profile&amp;rsquo; on and off in my test environment so far. (Doing extra work is going to have more impact on the &lt;em&gt;server&lt;/em&gt; no matter what you&amp;rsquo;re doing. I&amp;rsquo;m just saying it doesn&amp;rsquo;t seem to skew my measurements.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not a sponsored post, I just think this is a cool feature and I&amp;rsquo;m glad it&amp;rsquo;s now free. If you&amp;rsquo;d like to check out &lt;a href="https://www.sqlsentry.com/products/plan-explorer/sql-server-query-view"&gt;Plan Explorer, it&amp;rsquo;s over here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Setting up Free Blocking Alerts and Deadlock Monitoring (Dear SQL DBA Episode 17)</title><link>https://kendralittle.com/2016/09/29/setting-up-free-blocking-alerts-and-deadlock-monitoring-dear-sql-dba-episode-17/</link><pubDate>Thu, 29 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/29/setting-up-free-blocking-alerts-and-deadlock-monitoring-dear-sql-dba-episode-17/</guid><description>&lt;p&gt;What tools in SQL Server will notify you about blocking and help track the queries behind your toughest blocking and deadlocking problems?&lt;/p&gt;
&lt;p&gt;Watch the 21 minute video, subscribe to &lt;a href="https://kendralittle.com/dearsqldba/"&gt;the podcast&lt;/a&gt;, or read the episode notes and links below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;What is the best way to set up blocking and deadlock alerts on the server? I want to be notified automatically without any impact on the prod server.&lt;/p&gt;
&lt;p&gt;I have tried alerts with SQL server performance condition alerts with SQL server agent. They do not show the queries or tables involved etc?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/mWzHsqSbsSo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Woo hoo, I love this question!&lt;/p&gt;
&lt;p&gt;So first off, I&amp;rsquo;m going to answer this discussing the free, built-in tools with SQL Server. If you have a budget for custom monitoring tools, you can buy fancy tools that have customized notifications for blocking and which capture the queries and plans involved. If that&amp;rsquo;s the case, set up free trials against a test system.&lt;/p&gt;
&lt;p&gt;But not everyone has budget for every single SQL Server instance. So it&amp;rsquo;s extremely useful to know what SQL Server offers to help you with this.&lt;/p&gt;
&lt;p&gt;And by the way, if you&amp;rsquo;re going to be at the SQLPASS Summit in Seattle in just under a month, I&amp;rsquo;m giving a session that shows different blocking scenarios. Come see my session, &lt;a href="http://www.sqlpass.org/summit/2016/Sessions/Details.aspx?sid=47667"&gt;The Great Performance Robbery: Locking Problems and Solutions on Thursday, Oct 27th at 10:45AM in room 6C&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="free-simple-blocking-notifications"&gt;Free, simple blocking notifications&lt;/h2&gt;
&lt;p&gt;I like to set up blocking notifications with a simple SQL Server agent alert on the &amp;ldquo;SQLServer: General Statistic: Processes Blocked&amp;rdquo; performance counter.&lt;/p&gt;
&lt;p&gt;This will &lt;em&gt;not&lt;/em&gt; give you the queries involved in the blocking &amp;ndash; don&amp;rsquo;t worry, we&amp;rsquo;ll cover tracking that in the next step.&lt;/p&gt;
&lt;p&gt;This alert is low impact and it will let you know when you need to look at the SQL Server.&lt;/p&gt;
&lt;p&gt;To get this alert to work, you&amp;rsquo;ll need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure the SQL Server Agent service to auto start&lt;/li&gt;
&lt;li&gt;Set up database mail, enable it on the  SQL Server Agent, and then restart the SQL Server Agent&lt;/li&gt;
&lt;li&gt;Configure an Operator in the SQL Server Agent&lt;/li&gt;
&lt;li&gt;Create a new &amp;lsquo;performance&amp;rsquo; style alert, base it on the &amp;ldquo;Processes Blocked&amp;rdquo; counter, and tell it who to notify&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The SQL Agent doesn&amp;rsquo;t poll counters constantly - and we want this to be lightweight, so that&amp;rsquo;s a good thing. It will only poll every 15-30 seconds, and there&amp;rsquo;s no published guaranteed SLA on that polling frequency.&lt;/li&gt;
&lt;li&gt;If you really need something more sensitive and reliable, you need a monitoring system fully independent / outside of the SQL Server to be polling in and checking it for availability and performance.&lt;/li&gt;
&lt;li&gt;You can configure the alert to only fire every X minutes. I highly recommend that, so you don&amp;rsquo;t get an inbox of alerts every 20 seconds&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Create some blocking in a test database or in tempdb and make sure the alert works.&lt;/p&gt;
&lt;p&gt;I have example code to create blocking and deadlocks for your dev environments in my post, &lt;a href="https://kendralittle.com/2016/09/13/deadlock-code-for-the-wideworldimporters-sample-database/"&gt;Deadlock Code for the WorldWideImporters Sample Database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For production databases, you can create a temp table and write similar code to create blocking in those.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/lookout-query-comin-through-wide-300x150.png"
alt="lookout-query-comin-through-wide"&gt;
&lt;/figure&gt;
&lt;h2 id="findingthe-queries-involvedwith-the-blocked-process-report"&gt;Finding the queries involved with the Blocked Process Report&lt;/h2&gt;
&lt;p&gt;OK, we&amp;rsquo;ve got notifications. We need SQL Server to give us more information on who is involved in the blocking.&lt;/p&gt;
&lt;p&gt;I like to use the built-in Blocked Process Report for this. This has been in SQL Server for a long time, and it&amp;rsquo;s extremely useful.&lt;/p&gt;
&lt;p&gt;The Blocked Process Report shows you the &amp;ldquo;input buffer&amp;rdquo; of the commands involved - it may be partial information and not the full text of the query. It will also show you the login name for who is running what, and the type of lock requests involved.&lt;/p&gt;
&lt;p&gt;The Blocked Process Report is pretty lightweight, because SQL Server has to frequently wake up and look for blocking situations that can&amp;rsquo;t resolve themselves. By default, the deadlock monitor wakes up every 5 seconds and looks around to see if there is a deadlock which it needs to break. You may enable a feature called the &amp;lsquo;Blocked Process Report&amp;rsquo; that tells SQL Server to additionally issue a report on any blocking which it finds.&lt;/p&gt;
&lt;p&gt;To get this to work, you need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable the sp_configure option for the blocked process threshold. This defaults to &amp;lsquo;0&amp;rsquo;, which is off. You configure the threshold to the number of seconds you&amp;rsquo;d like the threshold to be. This should be a value of 5 or higher, because making the deadlock monitor run constantly could tank your performance. A good &amp;lsquo;starting&amp;rsquo; value is 30 seconds.&lt;/li&gt;
&lt;li&gt;You also need to set up a trace to collect an event called the &amp;lsquo;blocked process report&amp;rsquo;. Setting the threshold causes the event to be output, but SQL Server won&amp;rsquo;t collect it for you unless you start a SQL Trace or an Extended events trace that collects that event.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you have the trace file, you can copy it off of the production server to interpret it.&lt;/p&gt;
&lt;p&gt;Michael J Swart has written a great free tool called the Blocked Process Report Viewer to help interpret the blocking chains. It&amp;rsquo;s free at &lt;a href="https://sqlblockedprocesses.codeplex.com/"&gt;https://sqlblockedprocesses.codeplex.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The viewer makes it easier to see the root of the blocking chain and who was blocking whom.&lt;/p&gt;
&lt;p&gt;This trace is pretty lightweight, but with any trace you want to make sure that you don&amp;rsquo;t add a bunch of events that you don&amp;rsquo;t need, and that you periodically clean up the files and don&amp;rsquo;t let it impact drive space.&lt;/p&gt;
&lt;h2 id="when-i-talk-about-running-traces-i-dont-mean-running-profiler"&gt;When I talk about running traces, I don&amp;rsquo;t mean running Profiler&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re entering dangerous territory here. Whenever you talk about tracing in SQL Server these days, someone gets offended.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what you need to know. There&amp;rsquo;s two main ways to run a trace:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SQL Trace. This is the old school option. You can run this using&amp;hellip;
&lt;ol&gt;
&lt;li&gt;The Profiler client (I don&amp;rsquo;t like this option)&lt;/li&gt;
&lt;li&gt;A Server Side trace scripted out from Profiler (much better!).  You can get up to speed on Server Side Traces reading &lt;a href="http://www.toadworld.com/platforms/sql-server/w/wiki/10400.the-server-side-trace-what-why-and-how"&gt;this article on generating a service side trace by Jen McCown&lt;/a&gt;. (Note that she wrote this article back in 2009. That&amp;rsquo;s fine, SQLTrace hasn&amp;rsquo;t been changing since then.)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Extended Events. This is much easier to use on SQL Server 2012 and higher than in previous versions because a GUI was introduced in Management Studio for it under Object Explorer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I do not like leaving the Profiler application running because I&amp;rsquo;ve seen it do everything from slowing down performance to filling up drives over the years. And creating Server Side traces isn&amp;rsquo;t very hard if you do want to use SQL Trace.&lt;/p&gt;
&lt;p&gt;I personally only like to have a trace running if I know I need it and am going to look at it. So I only enable this when I have a blocking problem. Whenever you choose to leave a trace running, you need to periodically check in on the files its created and clean up after it.&lt;/p&gt;
&lt;h2 id="detecting-and-handlingdeadlocks"&gt;Detecting and handling deadlocks&lt;/h2&gt;
&lt;p&gt;What about locking problems where SQL Server has to step in and kill one of the queries?&lt;/p&gt;
&lt;p&gt;You have a few built in options about how to get info on this. There are some trace flags that you can turn on which cause some information about who is involved in the deadlock to be printed to the SQL Server Error Log. This isn&amp;rsquo;t my preferred option because the information is very hard to parse through and read.&lt;/p&gt;
&lt;p&gt;I find it more helpful to get a &amp;lsquo;deadlock graph&amp;rsquo;, which is a picture of how the locking fight went down.&lt;/p&gt;
&lt;p&gt;On older versions of SQL Server, you can capture the deadlock graph with a server side trace.&lt;/p&gt;
&lt;p&gt;On newer versions of SQL Server, you can capture this with an Extended Events trace.&lt;/p&gt;
&lt;p&gt;A great resource for deciding how to capture deadlock information is Jonathan Kehayias&amp;rsquo; excellent Simple Talk article, &lt;a href="https://www.simple-talk.com/sql/database-administration/handling-deadlocks-in-sql-server/"&gt;Handling Deadlocks in SQL Server&lt;/a&gt;.  He covers how to collect the graphs, shows examples of how they look, and gets you started tackling them.&lt;/p&gt;
&lt;p&gt;If you get through this point and need to get &lt;em&gt;really&lt;/em&gt; fancy with deadlocks, Michael J Swart recently wrote about using Event Notifications to collect execution plans related to deadlocks in his post, &amp;ldquo;&lt;a href="http://michaeljswart.com/2016/09/build-your-own-tools/"&gt;Build Your Own Tools&lt;/a&gt;&amp;rdquo;. Just don&amp;rsquo;t try to run before you walk: this is pretty advanced stuff and you need to be comfortable using Service Broker, which is part of Event Notifications behind the scenes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Updates, Oct 12, 2016&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deadlock alerting: While it&amp;rsquo;s always better for the application itself to catch, handle, and log/alert on failed queries (not just deadlocks, but timeouts and anything else)&amp;hellip; if your application can&amp;rsquo;t do that, and you can&amp;rsquo;t change it, check out this &lt;a href="http://sqlmag.com/blog/enabling-email-alerts-sql-server-deadlocks"&gt;SQL Magazine article by Michael Campbell on alerting on deadlocks from SQL Server&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Also, thanks to Johan for pointing out that the free &lt;a href="https://sentryone.com/plan-explorer"&gt;SQL Sentry Plan Explorer&lt;/a&gt; client tool is also able to display deadlock graphs. Just save them as an XDL file and you can open and view them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-recap---getting-more-info-on-blocking"&gt;Quick recap - getting more info on blocking&lt;/h2&gt;
&lt;p&gt;A fast rundown of the free, built-in tools we covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I like to use a simple, light, performance alert in the SQL Server agent for notification about blocking&lt;/li&gt;
&lt;li&gt;I like the Blocked Process report to find out who&amp;rsquo;s blocking whom - collected by a server side SQL Trace or Extended events&lt;/li&gt;
&lt;li&gt;I find collecting deadlock graphs with either a server side SQL Trace or Extended Events to be the most helpful way to figure out who&amp;rsquo;s involved in the nastiest blocking tangles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="want-to-submit-a-dear-sql-dba-question"&gt;Want to submit a Dear SQL DBA Question?&lt;/h2&gt;
&lt;p&gt;Want clarification on some of the basics? Got a question that jumped into your mind reading or listening to this? I&amp;rsquo;d love to hear it&amp;ndash; &lt;a href="https://kendralittle.com/submit-a-dear-dba-question/"&gt;asking is always free and easy&lt;/a&gt;!&lt;/p&gt;</description></item><item><title>Measuring Query Duration: SSMS vs SQL Sentry Plan Explorer</title><link>https://kendralittle.com/2016/09/27/measuring-query-duration-ssms-vs-sql-sentry-plan-explorer/</link><pubDate>Tue, 27 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/27/measuring-query-duration-ssms-vs-sql-sentry-plan-explorer/</guid><description>&lt;p&gt;Every query tuner wants to explain exactly how much faster we made a query.&lt;/p&gt;
&lt;p&gt;But sometimes SQL Server Management Studio adds noticeable overhead to the query duration. For relatively fast queries that return more than a few rows, just the overhead of displaying the results can skew your duration metric.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/How-long-did-that-query-really-take-300x300.png"
alt="how-long-did-that-query-really-take" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Spoiler, for those short on time: executing your queries from the &lt;a href="https://www.sqlsentry.com/products/plan-explorer/sql-server-query-view"&gt;SQL Sentry Plan Explorer&lt;/a&gt; client can be handy because it always discards results, shows you duration, CPU, reads, and writes, &lt;em&gt;and&lt;/em&gt; will display a message if you mess up your TSQL and get a parsing error. It&amp;rsquo;s free, and it&amp;rsquo;s a client tool with no need to install anything on the SQL Server itself.&lt;/p&gt;
&lt;h2 id="sql-server-management-studio-bloats-duration-a-bit"&gt;SQL Server Management Studio bloats duration a bit&lt;/h2&gt;
&lt;p&gt;I frequently use the command &lt;a href="https://msdn.microsoft.com/en-us/library/ms190287.aspx"&gt;SET STATISTICS TIME ON&lt;/a&gt; to tell SQL Server to print information about how long my query took to the &amp;lsquo;Messages&amp;rsquo; tab in SSMS. This is an easy, convenient tool to use interactively as you rewrite a query or tweak indexes in a test environment.&lt;/p&gt;
&lt;p&gt;I typically look at the &amp;lsquo;CPU time&amp;rsquo; metric when tuning instead of &amp;rsquo;elapsed time&amp;rsquo; (duration). This can work well for tuning because you&amp;rsquo;re measuring how much more efficient you made the  query in terms of CPU cycles.&lt;/p&gt;
&lt;p&gt;But &amp;lsquo;CPU time&amp;rsquo; isn&amp;rsquo;t perfect, and it can get a little weird for reporting results to users, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the query uses parallelism, CPU time can be higher than the duration &amp;ndash; which may make the query seem &amp;ldquo;slower&amp;rdquo; than it actually is to anyone reading a report&lt;/li&gt;
&lt;li&gt;&amp;rsquo;elapsed time&amp;rsquo; includes all the time that it takes to display the results in Management Studio, which is probably a different duration than it would take to return the results to an application server. If you&amp;rsquo;re just returning a few rows, this may be negligible&amp;ndash; but once it gets into the thousands of rows, it can be very noticeable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-about-discard-results-after-execution-in-ssms"&gt;What about &amp;lsquo;discard results after execution&amp;rsquo; in SSMS?&lt;/h3&gt;
&lt;p&gt;SSMS has a setting in the &amp;ldquo;Query&amp;rdquo; menu&amp;rsquo;s &amp;ldquo;Query Options&amp;rdquo; panel that tells it to throw away the query results.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Discard-Results.jpg"
alt="discard-results"&gt;
&lt;/figure&gt;
&lt;p&gt;Unfortunately, this also discards everything that displays on the &amp;lsquo;Messages&amp;rsquo; tab, too.&lt;/p&gt;
&lt;p&gt;In other words, you won&amp;rsquo;t see your SET STATISTICS TIME information.&lt;/p&gt;
&lt;p&gt;And worse, if you make a change to your TSQL so that it doesn&amp;rsquo;t even parse, you won&amp;rsquo;t see any errors. It&amp;rsquo;ll just look like it suddenly became &lt;em&gt;very very fast&lt;/em&gt;. If you&amp;rsquo;re like me, that will fool you for a second, and you&amp;rsquo;ll be like, &amp;ldquo;&lt;em&gt;I AM THE SMARTEST PERSON IN THE WORLD!&lt;/em&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Until you realize that your query is just silently failing.&lt;/p&gt;
&lt;h3 id="what-about-includeclient-statistics"&gt;What about &amp;lsquo;Include Client Statistics&amp;rsquo;?&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s a little button on the SSMS toolbar that tells it to start tracking some metrics for your session:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Include-Client-Statistics.jpg"
alt="include-client-statistics"&gt;
&lt;/figure&gt;
&lt;p&gt;You can combine this with &amp;lsquo;discard results after execution&amp;rsquo;. Your client statistics won&amp;rsquo;t get discarded, and it will even track your average metrics across multiple runs of your query, like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Client-Statistics-Metrics.jpg"
alt="client-statistics-metrics"&gt;
&lt;/figure&gt;
&lt;p&gt;I like the concept of this, but&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I don&amp;rsquo;t love having to discard results after execution (because I fat-finger the TSQL &lt;em&gt;a lot&lt;/em&gt; and would really like to see those parsing errors, thanks)&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t have the option to see logical reads (which I could get with SET STATISTICS IO), and it doesn&amp;rsquo;t know about CPU time. It&amp;rsquo;s just measuring client statistics, like the name says.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so I never find myself using Client Statistics much. If it was Server Statistics for the query, that&amp;rsquo;d be awesome! Oh well.&lt;/p&gt;
&lt;h2 id="sql-sentry-plan-explorer-makes-this-a-bit-easier"&gt;SQL Sentry Plan Explorer makes this a bit easier&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been opening query plans in SQL Sentry&amp;rsquo;s &amp;lsquo;Plan Explorer&amp;rsquo; tool for years, but I never ran a query from it until this week. I&amp;rsquo;d just never really thought about it before.&lt;/p&gt;
&lt;p&gt;To run a query from Plan Explorer, click the &amp;lsquo;Get Actual Plan&amp;rsquo; button. A pop up lets you know it&amp;rsquo;s going to discard the results, but it will really be running that query (so don&amp;rsquo;t go insert/update/delete/truncating if you don&amp;rsquo;t really mean it).&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Running-From-Plan-Explorer-1.png"
alt="running-from-plan-explorer"&gt;
&lt;/figure&gt;
&lt;p&gt;When the results come back, the first thing you&amp;rsquo;ll probably notice is a picture of the execution plan. But if you look up at the top of the window in the results pane, you can find Duration and CPU time there:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Duration-and-CPU-in-Plan-Explorer.jpg"
alt="duration-and-cpu-in-plan-explorer"&gt;
&lt;/figure&gt;
&lt;h3 id="what-if-your-query-fails"&gt;What if your query fails?&lt;/h3&gt;
&lt;p&gt;And if you&amp;rsquo;re like me, and you occasionally get a little too creative in your TSQL, it doesn&amp;rsquo;t just silently fail and tell you the query was fast. It&amp;rsquo;ll clue you into your error at the bottom of Plan Explorer:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Syntax-Error-Plan-Explorer.jpg"
alt="syntax-error-plan-explorer"&gt;
&lt;/figure&gt;
&lt;h2 id="im-not-breaking-up-with-management-studio"&gt;I&amp;rsquo;m not breaking up with Management Studio&lt;/h2&gt;
&lt;p&gt;SQL Server Management Studio will still remain my primary client tool. It&amp;rsquo;s really great for general purpose use - that hasn&amp;rsquo;t changed. I&amp;rsquo;ll still use SET STATISTICS TIME for a lot of general purpose tuning: it&amp;rsquo;s quick, it&amp;rsquo;s easy, it&amp;rsquo;s built in.&lt;/p&gt;
&lt;p&gt;For fine tuning queries were performance is really important, and where I want a more accurate view of duration while I&amp;rsquo;m looking at execution plans, Plan Explorer is super helpful.&lt;/p&gt;
&lt;p&gt;Thanks for making it &lt;a href="https://www.sqlsentry.com/products/plan-explorer/sql-server-query-view"&gt;completely free, SQL Sentry&lt;/a&gt;!&lt;/p&gt;</description></item><item><title>Which is Worse: an Unused Index, or an Un-Indexed Foreign Key? (Dear SQL DBA Episode 16)</title><link>https://kendralittle.com/2016/09/22/indexing-foreign-keys-guidelines/</link><pubDate>Thu, 22 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/22/indexing-foreign-keys-guidelines/</guid><description>&lt;p&gt;Should you always index your foreign keys? What if you index them, and then the index never gets used?&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Fe4l8ymtQ9k?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;We recently had a SQL Server performance assessment. It remarked on two things that made me think:&lt;/p&gt;
&lt;p&gt;1 ) tables with foreign keys but missing supporting index 2 ) tables with indexes that are not used&lt;/p&gt;
&lt;p&gt;But in our case the remark in Case 2 was on a index that supports a foreign key!&lt;/p&gt;
&lt;p&gt;Curtain down!&lt;/p&gt;
&lt;p&gt;Now to my question, in which cases should you as a rule create indexes to support a foreign key?&lt;/p&gt;
&lt;p&gt;Regards, The Indexer Who Can&amp;rsquo;t Win&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;LOL. I love this one!&lt;/p&gt;
&lt;p&gt;Clearly, the solution is to write some meaningless queries that use every unused foreign key indexes, right? :D&lt;/p&gt;
&lt;h2 id="quick-background---whats-a-foreign-key"&gt;Quick background - what&amp;rsquo;s a foreign key?&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Foreign-key-parent-child-kendra-little-1.jpg"
alt="foreign-key-parent-child-kendra-little"&gt;
&lt;/figure&gt;
&lt;p&gt;Foreign keys are a great way to make sure you have valid data in a relational database.&lt;/p&gt;
&lt;p&gt;I think of this in terms of parents and children. For example, let&amp;rsquo;s say I have two tables: dbo.FirstName, and dbo.Students.&lt;/p&gt;
&lt;p&gt;The dbo.FirstName table is the parent table. It has two columns, FirstNameId, and FirstName. This parent contains the valid, unique list of FirstNames. The FirstNameId column is defined as a Primary Key column.&lt;/p&gt;
&lt;p&gt;The dbo.Students table is the child table. It has many columns. FirstNameId is one of the columns.&lt;/p&gt;
&lt;p&gt;I can create a Foreign Key constraint on the child dbo.Students.FirstNameId that &lt;em&gt;references&lt;/em&gt; the parent, dbo.FirstNames.FirstNameId.&lt;/p&gt;
&lt;p&gt;This means that whenever I insert a row into dbo.Students, SQL Server will check and make sure that the FirstNameId I use is a valid row in the parent table, dbo.FirstNames.&lt;/p&gt;
&lt;p&gt;You can get creative with foreign keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The parent and child key columns can be in the same table&lt;/li&gt;
&lt;li&gt;You can have multiple columns in your foreign key (the number of columns and data types have to match between parent and child)&lt;/li&gt;
&lt;li&gt;The parent key can even be &lt;a href="https://kendralittle.com/2016/09/08/unique-constraints-vs-unique-indexes/"&gt;a unique index instead of a primary key or unique constraint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="its-a-good-practice-to-index-your-foreign-keys"&gt;It&amp;rsquo;s a good practice to index your foreign keys&lt;/h2&gt;
&lt;p&gt;To be clear, you don&amp;rsquo;t have a choice about indexing on the &amp;lsquo;parent&amp;rsquo; side of the foreign key. The referenced parent key column(s) has to have an index. (Primary keys and unique constraints are all backed by an index.)&lt;/p&gt;
&lt;p&gt;You have a choice about whether to index the columns in the child table - in my example, on dbo.Students.FirstNameId.&lt;/p&gt;
&lt;p&gt;I generally do index the child keys, because it&amp;rsquo;s very common for queries to join between the parent and child columns of a foreign key So there&amp;rsquo;s a good likelihood you&amp;rsquo;re going to need an index there.&lt;/p&gt;
&lt;p&gt;Erin Stellato wrote a great post on SQLPerformance.com with example code showing why indexing a foreign key can make a big performance difference. It&amp;rsquo;s called &amp;ldquo;&lt;a href="http://sqlperformance.com/2012/11/t-sql-queries/benefits-indexing-foreign-keys"&gt;The Benefits of Indexing Foreign Keys&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;There will be some times when you want to make an exception. (More on this soon.)&lt;/p&gt;
&lt;h2 id="what-about-those-unused-index-warnings"&gt;What about those &amp;lsquo;unused index&amp;rsquo; warnings?&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Lesser-Weevil-300x300.png"
alt="lesser-weevil" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;Whomever ran your performance assessment didn&amp;rsquo;t have time to look at this very deeply &amp;ndash; or if they did, they didn&amp;rsquo;t explain it in detail. I can&amp;rsquo;t really criticize them too much, I&amp;rsquo;ve had egg on my own face before.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a couple of possibilities about why indexes on your foreign keys might not be used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No queries are being run that join between the parent and child table.&lt;/li&gt;
&lt;li&gt;Queries are being run, but they don&amp;rsquo;t like the index because it doesn&amp;rsquo;t &amp;lsquo;cover&amp;rsquo; the query &amp;ndash; so they&amp;rsquo;re doing something else. They could be scanning the base table or using a near-duplicate index.
&lt;ul&gt;
&lt;li&gt;If there is another index that leads on the same keys that is pulling all the weight and covers the foreign key better, the narrow index keyed only on the foreign key columns isn&amp;rsquo;t adding value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would look for the &amp;ldquo;lesser evil&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;To check if an unused index is really a problem, ask:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the unused index so large that it takes up significant room in the data file / backups / restores?&lt;/li&gt;
&lt;li&gt;Does the table have such a high rate of modifications that the index may be a performance problem?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If either of these are a big concern, I&amp;rsquo;d consider dropping the index on the foreign keys.&lt;/p&gt;
&lt;p&gt;However, I would want to monitor it for some time to make sure that there isn&amp;rsquo;t a workload that really cares about that index which just hasn&amp;rsquo;t run in a while.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Index usage gets reset when the database comes online&lt;/li&gt;
&lt;li&gt;In many versions of SQL Server, index rebuilds also reset this information. See my post &amp;ldquo;&lt;a href="https://kendralittle.com/2016/03/07/sql-server-2016-rc0-fixes-index-usage-stats-bug-missing-indexes-still-broken/"&gt;What Resets Index Usage Stats and Missing Index DMVs&lt;/a&gt;?&amp;rdquo; for details.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-might-you-want-to-not-use-a-simple-index-on-foreign-key-columns"&gt;When might you want to not use a simple index on foreign key columns?&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s always an exception, right?&lt;/p&gt;
&lt;p&gt;Here are some examples I can think of when I might not want a simple index on a child key:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The foreign key index might help performance significantly if it&amp;rsquo;s widened to &amp;ldquo;cover&amp;rdquo; critical queries. In this case, adding additional key and/or included columns may improve query performance (Fairly common)&lt;/li&gt;
&lt;li&gt;For tables with very high modifications rates which are performance sensitive, when I know for sure I don&amp;rsquo;t need to index the foreign keys, they just add overhead and don&amp;rsquo;t help. You need to be &lt;em&gt;sure&lt;/em&gt; you don&amp;rsquo;t need the foreign key index, or you could run into a major blocking problem because they&amp;rsquo;re missing, though. (Edge case)&lt;/li&gt;
&lt;li&gt;When the data in the foreign key columns is very non-selective and it&amp;rsquo;s a super narrow table, indexing the foreign key may not make a huge performance difference. (Edge case)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="i-think-sql-server-should-index-foreign-keys-automatically"&gt;I think SQL Server should index foreign keys automatically&lt;/h2&gt;
&lt;p&gt;I actually think it would be a nice feature for SQL Server to index foreign key columns automatically, as long as it let you specify not to do so, and also let you alter/drop the indexes later.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a fun discussion of this on Greg Low&amp;rsquo;s blog from 2008 in his post, &amp;ldquo;&lt;a href="http://sqlblog.com/blogs/greg_low/archive/2008/07/29/indexing-foreign-keys-should-sql-server-do-that-automatically.aspx"&gt;Indexing Foreign Keys - Should SQL Server Do that Automatically&lt;/a&gt;?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I feel like this is a &amp;ldquo;nice to have&amp;rdquo; feature, but I don&amp;rsquo;t feel strongly about the SQL Server product team spending time on it. They&amp;rsquo;ve got other features that I&amp;rsquo;d like to have more, because in this case I think other features help compensate a bit.&lt;/p&gt;
&lt;p&gt;SQL Server&amp;rsquo;s &amp;ldquo;missing index&amp;rdquo; feature isn&amp;rsquo;t perfect, but it&amp;rsquo;s pretty darn good at complaining. If you forget to index a foreign key that&amp;rsquo;s critical to queries or if the index gets dropped, SQL Server is pretty likely to start asking for an index.&lt;/p&gt;
&lt;p&gt;So if you&amp;rsquo;re looking at your missing index warnings, you&amp;rsquo;re likely to figure out that an index on the foreign key column can speed up your queries (maybe without even realizing it&amp;rsquo;s related to a foreign key).&lt;/p&gt;
&lt;p&gt;I do recommend handling the missing index feature carefully, like it&amp;rsquo;s a small child who really wants candy in the grocery store checkout line. But that&amp;rsquo;s a story for another day.&lt;/p&gt;
&lt;h2 id="summing-it-all-up"&gt;Summing it all up&lt;/h2&gt;
&lt;p&gt;So, which is Worse: an Unused Index, or an Un-Indexed Foreign Key? Usually an un-indexed foreign key is worse.&lt;/p&gt;</description></item><item><title>Index Tuning Decision Tree for SQL Server</title><link>https://kendralittle.com/2016/09/20/index-tuning-decision-tree-for-sql-server/</link><pubDate>Tue, 20 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/20/index-tuning-decision-tree-for-sql-server/</guid><description>&lt;p&gt;I recently mapped out my thought process for how I approach a new instance of SQL Server when it comes to index tuning.&lt;/p&gt;
&lt;p&gt;It now looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Index-Tuning-Decision-Tree-SQL-Server-Kendra-Little.png"
alt="Index Tuning Decision Tree SQL Server-Kendra-Little"&gt;
&lt;/figure&gt;
&lt;h2 id="highlight-can-i-use-query-store"&gt;Highlight: Can I use Query Store?&lt;/h2&gt;
&lt;p&gt;One of the first things I think about is whether the new 2016 Query Store option is available to collect query runtime statistics and execution plans. Information on query duration, reads, cpu use, and execution plans are so critical to index tuning that I care a ton about this new feature.&lt;/p&gt;
&lt;p&gt;And it is a &lt;em&gt;new&lt;/em&gt; feature. It&amp;rsquo;s even had its first big bugfix &amp;ndash; if you&amp;rsquo;re running it on something other than Enterprise or Developer Edition, make sure you&amp;rsquo;ve tested and installed CU1, which contains &lt;a href="https://support.microsoft.com/en-us/kb/3178297"&gt;this fix for query store cleanup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a big fan of SQL Server&amp;rsquo;s plan cache and index management dynamic management views &amp;ndash; but I love that Query Store takes away the mystery of wondering what might be missing from the cache, or which &lt;a href="https://connect.microsoft.com/SQLServer/feedback/details/2446044?utm_content=bufferc91b6&amp;amp;utm_medium=social&amp;amp;utm_source=twitter.com&amp;amp;utm_campaign=buffer"&gt;missing index requests might have been cleared by an index rebuild&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="observation-tuning-indexes-is-most-effective-when-you-analyze-thetop-execution-plans-to-design-your-indexes--not-the-missing-index-dmvs"&gt;Observation: Tuning indexes is most effective when you analyze the top execution plans to design your indexes &amp;ndash; not the missing index DMVs&lt;/h2&gt;
&lt;p&gt;When I first began tuning indexes in SQL Server, I largely reviewed and followed missing index suggestions in the missing index DMVs. I learned to combine those suggestions together and with indexes on the tables.&lt;/p&gt;
&lt;p&gt;My tuning style has evolved from this, though. SQL Server&amp;rsquo;s index recommendations are useful, but they&amp;rsquo;re very rough - sometimes they suggest columns for the includes which you don&amp;rsquo;t absolutely need. Sometimes they suggest a column as an include that would be better in the key. Sometimes they overestimate the benefit the index would provide. And sometimes you just don&amp;rsquo;t get a suggestion at all.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not that the Missing Index feature doesn&amp;rsquo;t work, it&amp;rsquo;s simply that &lt;a href="https://technet.microsoft.com/en-us/library/ms345485(v=sql.105).aspx"&gt;the missing index feature is not designed to fine-tune an index workload&lt;/a&gt;. And that&amp;rsquo;s totally fair - those index requests are generated during query optimization, and that&amp;rsquo;s &lt;em&gt;definitely&lt;/em&gt; something that we want to be fast!&lt;/p&gt;
&lt;p&gt;What I very much prefer these days is to look at the top running queries during the periods I want to tune. I like to examine the execution plans and CPU, reads, and duration for the statements along with the plans.&lt;/p&gt;
&lt;p&gt;I do still like to look at missing index suggestions, I just prefer to do it in the context of the plan asking for it.&lt;/p&gt;
&lt;p&gt;The reason that I love the whole concept of Query Store is that it&amp;rsquo;s a built in way to make this a whole lot easier!&lt;/p&gt;</description></item><item><title>Deadlock Code for the WideWorldImporters Sample Database</title><link>https://kendralittle.com/2016/09/13/deadlock-code-for-the-wideworldimporters-sample-database/</link><pubDate>Tue, 13 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/13/deadlock-code-for-the-wideworldimporters-sample-database/</guid><description>&lt;p&gt;If you haven&amp;rsquo;t checked out Microsoft&amp;rsquo;s &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;new WideWorldImporters sample database&lt;/a&gt; for 2016, it&amp;rsquo;s a pretty cool new little database. The database makes it easy to play around with new 2016 features, and it even ships with some cool little executables to run inserts in the &amp;ldquo;workload-drivers&amp;rdquo; folder.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Deadlock-Priority.png"
alt="Deadlock-Priority" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;I recently put together some code to reproduce a simple deadlock in WideWorldImporters. This isn&amp;rsquo;t related to the new features at all&amp;ndash; I was just exploring the sample database and writing some demos for locking and blocking. Deadlocks are easier to understand when you have hands-on code that you can step through and watch it happen live, rather than just being mystified by it when it happens later!&lt;/p&gt;
&lt;h2 id="setup---restore-wideworldimporters"&gt;Setup - Restore WideWorldImporters&lt;/h2&gt;
&lt;p&gt;All you need to do is download the &lt;a href="https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0"&gt;WideWorldImporters-Full.bak&lt;/a&gt; backup (121MB) and restore it to a test instance with Developer Edition running.&lt;/p&gt;
&lt;h2 id="lets-cause-a-deadlock"&gt;Let&amp;rsquo;s Cause a Deadlock&lt;/h2&gt;
&lt;p&gt;You will use two session windows to create your deadlock.&lt;/p&gt;
&lt;p&gt;In session window #1, run this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WideWorldImporters&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Run the BEGIN tran and the first statement in this session.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;We&amp;#39;re taking out a lock on the Countries table */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;TRANCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRAN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Countries&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LatestRecordedPopulation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LatestRecordedPopulation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IsoNumericCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;840&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Leaving that there, open session window #2, and run this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CityName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StateProvinceName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LatestRecordedPopulation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CountryName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cities&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StateProvinces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StateProvinceID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StateProvinceID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Countries&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CountryID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ctry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CountryID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StateProvinceName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Virginia&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code in session window #2 should be blocked &amp;ndash; you&amp;rsquo;ll see it sitting there executing.&lt;/p&gt;
&lt;p&gt;Back in session window #1, run this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StateProvinces&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LatestRecordedPopulation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LatestRecordedPopulation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StateProvinceCode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;VA&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Session window #1 should tell you that 1 row was affected. It&amp;rsquo;s done!&lt;/p&gt;
&lt;p&gt;Look back in session window #2, though. You should see the following message:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 1205, Level 13, State 51, Line 1&lt;/p&gt;
&lt;p&gt;Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="a-deadly-embrace"&gt; A &amp;ldquo;deadly embrace&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;SQL Server&amp;rsquo;s deadlock manager woke up, looked around, and saw that our two session windows were stuck. They each were requesting locks that the other session wouldn&amp;rsquo;t give up&amp;ndash; and if the deadlock manager didn&amp;rsquo;t break the deadlock, they&amp;rsquo;d be stuck there forever.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t set the deadlock priority on any of my transactions, so the deadlock manager picked the session that it thought would be the least work to roll back&amp;ndash; and it became the victim.&lt;/p&gt;
&lt;h2 id="how-to-learn-more-about-deadlocks"&gt;How to learn more about deadlocks&lt;/h2&gt;
&lt;p&gt;This repro code will get you started. It&amp;rsquo;s rerunnable: you can keep deadlocking and deadlocking those sessions.&lt;/p&gt;
&lt;p&gt;To teach yourself more about how the locks work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;a href="http://sqlblog.com/files/default.aspx"&gt;sp_WhoIsActive&lt;/a&gt; with @get_locks=1 from a 3rd session window at different points and observe lock grants and waits between the session&lt;/li&gt;
&lt;li&gt;Set up an extended events session to pick up the deadlock graph, reproduce the deadlock, and teach yourself to decode the graph. (Erin Stellato has a &lt;a href="http://www.sqlservercentral.com/stairway/134867/"&gt;free Stairway to Extended Events&lt;/a&gt; if you&amp;rsquo;re just getting started with those.&lt;/li&gt;
&lt;li&gt;What are your options for fixing this deadlock? Test out &lt;a href="https://kendralittle.com/2016/02/18/how-to-choose-rcsi-snapshot-isolation-levels/"&gt;optimistic locking,&lt;/a&gt; query rewrites, setting deadlock priority, and creating indexes to see what works (I&amp;rsquo;m not saying that all of them do in this case)&lt;/li&gt;
&lt;li&gt;What is Countries_Archive, and why does it show up in the lock graphs?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy learning!&lt;/p&gt;</description></item><item><title>Unique Constraints vs Unique Indexes</title><link>https://kendralittle.com/2016/09/08/unique-constraints-vs-unique-indexes/</link><pubDate>Thu, 08 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/08/unique-constraints-vs-unique-indexes/</guid><description>&lt;p&gt;Unique constraints and unique nonclustered indexes have a lot in common: unique constraints are implemented with a unique index behind the scenes.&lt;/p&gt;
&lt;p&gt;While unique nonclustered indexes have a couple of additional features, I can still think of a scenario where it might be best to use unique constraints.&lt;/p&gt;
&lt;h2 id="unique-indexes-more-flexible"&gt;Unique Indexes: More flexible!&lt;/h2&gt;
&lt;h3 id="1-you-can-add-included-columns-to-a-unique-index"&gt;1. You can add included columns to a unique index&lt;/h3&gt;
&lt;p&gt;Included columns can potentially make unique indexes more useful to support query performance. Uniqueness is only enforced for the key columns defined in the index &amp;ndash; so adding the included columns doesn&amp;rsquo;t change what is required to be unique.&lt;/p&gt;
&lt;h3 id="2-you-can-add-a-filter-to-a-unique-index---particularly-handy-when-it-comes-to-nulls"&gt;2. You can add a filter to a unique index - particularly handy when it comes to NULLs&lt;/h3&gt;
&lt;p&gt;SQL Server is a little peculiar when it comes to NULLS and uniqueness: it considers NULL to be a value. If I create a unique constraint on the nullable column &amp;lsquo;Foo&amp;rsquo;, I can have only one row where Foo is NULL.&lt;/p&gt;
&lt;p&gt;If you need to have multiple rows where Foo is NULL, but want to enforce uniqueness for non-null rows, you can &lt;a href="http://sqlmag.com/blog/whats-good-use-unique-filtered-index"&gt;create a filtered unique index where Foo IS NOT NULL&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="3-foreign-keys-can-reference-non-filtered-unique-indexes"&gt;3. Foreign keys can reference non-filtered unique indexes&lt;/h3&gt;
&lt;p&gt;You can also define foreign keys that reference a unique index, just like you can against a primary key constraint or a unique constraint.&lt;/p&gt;
&lt;p&gt;So given these things, is there still a case for sometimes using unique constraints? I think so.&lt;/p&gt;
&lt;h2 id="unique-constraints-potentially-safer-from-accidental-drops"&gt;Unique Constraints: Potentially safer from accidental drops&lt;/h2&gt;
&lt;p&gt;Some developers need to design a schema for a database where they won&amp;rsquo;t always control the index tuning. The database may be distributed as part of software that is managed by others.&lt;/p&gt;
&lt;p&gt;One potential problem with unique indexes is procedural: a unique index might be accidentally dropped by a DBA who is working to reduce the amount of indexes in a database. The DBA may just not notice that the indexes are enforcing uniqueness if they write a script quickly to find &amp;ldquo;unused&amp;rdquo; indexes and forget to exclude unique indexes.&lt;/p&gt;
&lt;p&gt;However, if you try to drop a unique constraint with a &amp;lsquo;drop index&amp;rsquo; command, you&amp;rsquo;ll get an error. You need to remove it with an &lt;a href="https://msdn.microsoft.com/en-gb/library/ms190273.aspx"&gt;ALTER TABLE DROP CONSTRAINT&lt;/a&gt; command&amp;ndash; which is a bit less likely to be run by accident. In this case, using unique constraints might be potentially safer, as far as user error is concerned.&lt;/p&gt;</description></item><item><title>Estimated vs. Actual Number of Rows in Nested Loop Operators</title><link>https://kendralittle.com/2016/09/06/estimated-vs-actual-number-of-rows-in-nested-loop-operators/</link><pubDate>Tue, 06 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/06/estimated-vs-actual-number-of-rows-in-nested-loop-operators/</guid><description>&lt;p&gt;This is one of those little details that confused me a ton when I was first working with execution plans.&lt;/p&gt;
&lt;p&gt;One problem with learning to work with plans is that there&amp;rsquo;s just SO MUCH to look at. And it&amp;rsquo;s a bit spread out. So, even when looking at a single tooltip, things can be confusing.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s talk about the nested loop operator, who can be particularly weird to understand.&lt;/p&gt;
&lt;h2 id="meet-our-nested-loop"&gt;Meet our nested loop&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a nested loop from a SQL Server Execution plan:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Nested-Loop-1.png"
alt="Nested Loop"&gt;
&lt;/figure&gt;
&lt;p&gt;For every row that comes in from the top right index seek, SQL Server goes and does the bottom right index seek. Like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Nested-Loop-inner-and-outer.png"
alt="Nested Loop-inner and outer"&gt;
&lt;/figure&gt;
&lt;p&gt;When you hover over that bottom index seek (the inner input), things may look at first like they&amp;rsquo;re wrong with our nested loop.&lt;/p&gt;
&lt;h2 id="were-trained-early-to-compare-estimated-vs-actual-rows-in-plans"&gt;We&amp;rsquo;re trained early to compare estimated vs actual rows in plans&lt;/h2&gt;
&lt;p&gt;One of the first things we often learn when we&amp;rsquo;re looking at plans is that SQL Server uses estimates. And sometimes, those estimates are wrong. At first glance, this looks really wrong&amp;ndash; it estimated 11.5 rows, and actually got 20,825 rows!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Estimated-Vs-Actual-Rows.png"
alt="Estimated Vs Actual Rows"&gt;
&lt;/figure&gt;
&lt;p&gt;Similarly, we see these same wrong-looking numbers if we hover over the line between the nested loop operator and the &amp;ldquo;inner&amp;rdquo; seek:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Another-view-hovering-over-the-line.png"
alt="Another view- hovering over the line"&gt;
&lt;/figure&gt;
&lt;h2 id="read-estimated-number-of-rows-as-the-estimate-per-execution"&gt;Read &amp;ldquo;estimated number of rows&amp;rdquo; as the estimate per execution&lt;/h2&gt;
&lt;p&gt;With a nested loop, you have to remember to also look at the number of executions, and do a little math. The number of executions is on the tooltip of the seek itself, but I often have to do a double take to find it, because it&amp;rsquo;s so crowded. Here it is:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Estimated-Vs-Actual-Rows-With-Estimated-Executions.png"
alt="Estimated Vs Actual Rows With Estimated Executions"&gt;
&lt;/figure&gt;
&lt;p&gt;The estimate here is 11.5692 rows per execution * 2,055.56 executions = 23,782.22598 estimated rows.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s not terribly far off from the 29,969 rows that it ended up reading.&lt;/p&gt;
&lt;h2 id="when-you-see-what-looks-like-a-bad-estimate-take-a-second-look"&gt;When you see what looks like a bad estimate, take a second look&lt;/h2&gt;
&lt;p&gt;Check the estimated number of executions and do a little math. SQL Server may have known exactly what it was doing, after all.&lt;/p&gt;</description></item><item><title>Finding Your Voice as a Speaker (Dear SQL DBA Episode 15)</title><link>https://kendralittle.com/2016/09/01/finding-your-voice-as-a-speaker-dear-sql-dba-episode-15/</link><pubDate>Thu, 01 Sep 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/09/01/finding-your-voice-as-a-speaker-dear-sql-dba-episode-15/</guid><description>&lt;p&gt;Learn what it&amp;rsquo;s like to find and develop your voice as a technical speaker in this week&amp;rsquo;s episode of Dear SQL DBA.&lt;/p&gt;
&lt;p&gt;You can also &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;listen to this episode in a podcast&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/w7Ft2ymGmfc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;This episode is a little more personal than most. Today, I&amp;rsquo;m going to answer a question that I&amp;rsquo;ve gotten five or six times in the last couple of months from kind strangers on the internet:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear Kendra,&lt;/p&gt;
&lt;p&gt;What are you up to these days?&lt;/p&gt;
&lt;p&gt;Curious on the Internet&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="ive-been-rewriting-my-indexing-precon"&gt;I&amp;rsquo;ve been rewriting my indexing precon&lt;/h2&gt;
&lt;p&gt;It takes a while to write a full day of training. I wrote a full day session on indexing near the beginning of 2016. It took me several months to write it. I presented it a couple of times and it went extremely well, and I got lots of great feedback.&lt;/p&gt;
&lt;p&gt;I decided to write large portions of it to re-shape the narrative &lt;a href="http://www.sqlpass.org/summit/2016/Sessions/Details.aspx?sid=47583"&gt;for the SQL PASS Summit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I love teaching on indexes. I wanted to make this day of learning have as much of a flow and story to it as possible. And I wanted to really find my voice, and make this the best day of training that I&amp;rsquo;ve ever made.&lt;/p&gt;
&lt;p&gt;For me, this had two parts: the story, and the illustration.&lt;/p&gt;
&lt;h2 id="narrative---the-story-in-technical-examples"&gt;Narrative - the story in technical examples&lt;/h2&gt;
&lt;p&gt;I enjoy teaching by working through lots of example problems. And lots of technical people learn well by thinking through a problem, proposing different solutions, and then comparing different solutions.&lt;/p&gt;
&lt;p&gt;But raw examples just aren&amp;rsquo;t that much fun. I felt that I could improve the flow of the day.&lt;/p&gt;
&lt;p&gt;I decided to build the pre-con around an Odyssey-style adventure. In my new day of training, we set out to journey the world of rowstore indexes as a crew in a small boat, stopping in different locations along the way.&lt;/p&gt;
&lt;p&gt;In each module, we encounter a different &amp;ldquo;monster&amp;rdquo; which can be misleading or confusing. These are things like hash joins, bitmap probes, aggregate operators in execution plans.&lt;/p&gt;
&lt;p&gt;And any demo that I didn&amp;rsquo;t &lt;em&gt;love&lt;/em&gt; got re-written. I wanted each example to really shine in my own eyes as well as make sense as part of the story.&lt;/p&gt;
&lt;h2 id="narrative---story-in-illustration"&gt;Narrative - story in illustration&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been learning to draw again as part of the process. I wanted to illustrate the journey and the monsters.&lt;/p&gt;
&lt;p&gt;I drew a lot as a kid, and doodled in a lot of meetings as an adult. I mostly stopped drawing after starting a company, though. It made a lot more sense to hire a professional illustrator for art the company needed, and I didn&amp;rsquo;t find drawing relaxing anymore&amp;ndash; particularly if it involved a computer.&lt;/p&gt;
&lt;p&gt;But these days, I am interested in using illustration as part of my teaching. So I&amp;rsquo;ve been learning to draw the story as I go through it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m still a bit slow at drawing. But I&amp;rsquo;m getting faster - I try to draw every day. And I&amp;rsquo;m getting better at mentally designing drawings that I can actually carry out, too&amp;mdash; which is a big part of the process.&lt;/p&gt;
&lt;h2 id="finding-your-voice-as-a-speaker-takes-time"&gt;Finding your voice as a speaker takes time&lt;/h2&gt;
&lt;p&gt;When you first begin teaching, don&amp;rsquo;t worry about &amp;ldquo;your voice&amp;rdquo;. Worry about being coherent and breathing while you&amp;rsquo;re on stage teaching. That&amp;rsquo;s plenty to handle when you begin.&lt;/p&gt;
&lt;p&gt;As you continue to speak, and you have the basics under your belt, start to experiment a bit.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re planning presentations, think about who your audience is first.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is their job role?&lt;/li&gt;
&lt;li&gt;How many years of experience do they have?&lt;/li&gt;
&lt;li&gt;What do they struggle with, and what do they need to learn?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think about what style of story you want to tell them, and within it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do you want it to relate to your personal experiences, and if so, when and where will you share that? A story at the beginning? A recurring theme?&lt;/li&gt;
&lt;li&gt;Are there key insights or &amp;ldquo;aha&amp;rdquo; moments that you want to reinforce? How do those fit into the narrative?&lt;/li&gt;
&lt;li&gt;How do you want to close the story, and what tasks or tools should the audience take with them?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I just finished writing another session after completing the precon. It&amp;rsquo;s a new session on locking and blocking.&lt;/p&gt;
&lt;p&gt;Mapping the narrative out before I began writing it helped the structure and flow from the start.&lt;/p&gt;
&lt;h2 id="dear-sql-dba-will-be-taking-a-break-for-a-couple-of-weeks"&gt;Dear SQL DBA will be taking a break for a couple of weeks&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve got a few adventures going on during the next couple of weeks. I really like doing the podcast every week and decided against pre-recording short episodes.&lt;/p&gt;</description></item><item><title>Do Clustered Index Columns Count Against Max Nonclustered Key Size?</title><link>https://kendralittle.com/2016/08/30/do-clustered-index-columns-count-against-max-nonclustered-key-size/</link><pubDate>Tue, 30 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/30/do-clustered-index-columns-count-against-max-nonclustered-key-size/</guid><description>&lt;p&gt;SQL Server 2016 and Azure SQL Database have a lot of little perks. One little thing that changed is that the maximum key size allowed for nonclustered indexes was &lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/04/26/increased-nonclustered-index-key-size-with-sql-server-2016/"&gt;raised from 900 bytes to 1700 bytes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Whoa! That&amp;rsquo;s room for a lot more key columns in there. Bring on the SSDs! Load up the memory! &lt;em&gt;THE KEY COLUMNS  COMETH&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Well, maybe not so fast. Remember that larger nonclustered indexes not only use up more memory and storage, but also&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They increase backup time and resources&lt;/li&gt;
&lt;li&gt;More indexes means more index maintenance&lt;/li&gt;
&lt;li&gt;You gotta check &amp;rsquo;em all for corruption (not quite like Pokemon, but close enough)&lt;/li&gt;
&lt;li&gt;They require more space everywhere they are restored&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So make sure you really need all that junk in your nonclustered index trunk. Er, key.&lt;/p&gt;
&lt;p&gt;But even with the expanded size of key columns, sometimes I get asked a question: do columns that &amp;ldquo;secretly&amp;rdquo; get added to the key of a nonclustered index count against the maximum allowed nonclustered index key length?&lt;/p&gt;
&lt;p&gt;Spoiler, for those of you short on time: Key columns explicitly stated in your index definition are restricted to 900 or 1700 bytes (depending on SQL Server version as mentioned above). Clustered index key columns secretly added to the nonclustered index definition get an &lt;em&gt;extra&lt;/em&gt; 900 bytes to themselves.&lt;/p&gt;
&lt;h2 id="background-sql-server-often-sneaks-the-key-of-a-tablesclustered-index-into-the-key-of-each-nonclustered-index"&gt;Background: SQL Server often sneaks the key of a table&amp;rsquo;s clustered index into the key of each nonclustered index&lt;/h2&gt;
&lt;p&gt;Behind the scenes, SQL Server needs a unique way to identify every row in an index - and it also needs a way to find the exact same row in other indexes on the table.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s say you&amp;rsquo;ve got a nonclustered index that doesn&amp;rsquo;t enforce uniqueness: it&amp;rsquo;s just used to make reads faster.&lt;/p&gt;
&lt;p&gt;To make everything unique&amp;hellip;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center"&gt;Table Structure (rowstore B-Trees)&lt;/th&gt;
&lt;th style="text-align: center"&gt;Unique Nonclustered Index&lt;/th&gt;
&lt;th style="text-align: center"&gt;Non-Unique Nonclustered Index&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Unique Clustered Index&lt;/td&gt;
&lt;td style="text-align: center"&gt;CX key(s) added to included columns&lt;/td&gt;
&lt;td style="text-align: center"&gt;CX key(s) added to key column(s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Non-Unique Clustered Index&lt;/td&gt;
&lt;td style="text-align: center"&gt;CX key(s) + Uniquifier added to included columns&lt;/td&gt;
&lt;td style="text-align: center"&gt;CX key(s) + Uniquifier added to key column(s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Heap&lt;/td&gt;
&lt;td style="text-align: center"&gt;RID added to included columns&lt;/td&gt;
&lt;td style="text-align: center"&gt;RID added to key column(s)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The question is, when CX columns are snuck into the key, does it count against the max row size?&lt;/p&gt;
&lt;p&gt;They do NOT count. It&amp;rsquo;s easy to prove, let&amp;rsquo;s take a look.&lt;/p&gt;
&lt;h2 id="proving-that-secret-key-columns-dont-count"&gt;Proving that &amp;ldquo;secret&amp;rdquo; key columns don&amp;rsquo;t count&lt;/h2&gt;
&lt;p&gt;Just for fun, we&amp;rsquo;re going to prove that those index pants got more stretchy at the same time on SQL Server 2016.&lt;/p&gt;
&lt;p&gt;First, we create a table with three columns. Just to keep it from being lonely, we give it three rows.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeySizeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FourBytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AVeryWideColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1696&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ASmallColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Wee&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeySizeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AVeryWideColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mope&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;moop&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The maximum column length for all the columns in this table is 1703&amp;ndash; but let&amp;rsquo;s test what we can get away with.&lt;/p&gt;
&lt;p&gt;First, create our four byte unique clustered index:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cx_KeySizeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeySizeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FourBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now to test out that big key size! This two column index comes to 1700 per row:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nc_KeySizeTest_AVeryWideColumn_ASmallColumn&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeySizeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AVeryWideColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ASmallColumn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that works!&lt;/p&gt;
&lt;p&gt;What if we try to explicitly add the clustered index key to the end of the index (where SQL Server is going to put it, anyway&amp;ndash; cause this baby isn&amp;rsquo;t unique)?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nc_KeySizeTest_AVeryWideColumn_ASmallColumn_FourBytes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeySizeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AVeryWideColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ASmallColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FourBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ooooooo, that fails.&lt;/p&gt;
&lt;h2 id="msg-1944-level-16-state-1-nonclustered-index-key-size"&gt;Msg 1944, Level 16, State 1: nonclustered index key size&lt;/h2&gt;
&lt;p&gt;In failing, it gives us more info:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 1944, Level 16, State 1, Line 32
Index &amp;rsquo;nc_KeySizeTest_AVeryWideColumn_ASmallColumn&amp;rsquo; was not created because the index key size is at least 1704 bytes. The nonclustered index key size cannot exceed 1700 bytes. If the index key includes implicit key columns, the index key size cannot exceed 2600 bytes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="implicit-or-secret-key-columns-get-900-bytes-of-their-own"&gt; &amp;ldquo;Implicit&amp;rdquo; or &amp;ldquo;Secret&amp;rdquo; Key Columns get 900 bytes of their own&lt;/h2&gt;
&lt;p&gt;This makes sense, because the size limit of those columns is 900 bytes.&lt;/p&gt;
&lt;p&gt;But &amp;hellip; wouldn&amp;rsquo;t it also make sense for SQL Server to have recognized that FourBytes was going to be implicitly added to that index, anyway?&lt;/p&gt;
&lt;p&gt;Well, yes, that would be nice.&lt;/p&gt;
&lt;h2 id="but-kendra-you-didnt-really-prove-that-the-clustered-index-key-was-implicitly-added"&gt;But Kendra, you didn&amp;rsquo;t really prove that the clustered index key was implicitly added&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s true, the proof wasn&amp;rsquo;t entirely in that error message. We can use a bit of code to prove that the REAL key of the index named nc_KeySizeTest_AVeryWideColumn_ASmallColumn contains the column FourBytes, which we didn&amp;rsquo;t explicitly ask for.&lt;/p&gt;
&lt;p&gt;First, use the undocumented dynamic management view sys.dm_db_database_page_allocations to find the page number of an allocated index page:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocated_page_page_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_database_page_allocations&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;KeySizeTest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;detailed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nc_KeySizeTest_AVeryWideColumn_ASmallColumn&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_allocated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_iam_page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my case this landed at page 166584.&lt;/p&gt;
&lt;p&gt;I plug that page number into another undocumented command to return a bird&amp;rsquo;s eye system view of that data page, using this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This trace flag tells SQL Server to return the results of DBCC PAGE to your session window */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRACEON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3604&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* This looks at the index page. Swap in the page number for your database */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Database name, Data file number, Page Number, Page dump style */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DBCC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SQLIndexWorkbook&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;166584&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what the page really looks like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/DBCC-PAGE-KeyColumns.gif"
alt="DBCC PAGE KeyColumns"&gt;
&lt;/figure&gt;
&lt;p&gt;There are three key columns&amp;ndash; and FourBytes is in there at the end of the key, even though we didn&amp;rsquo;t ask for it.&lt;/p&gt;
&lt;h2 id="takeaways-on-max-key-length-and-things-to-remember"&gt;Takeaways on max key length and things to remember&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve gone a long way around the block. Here&amp;rsquo;s a little wrap-up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Just because you have more rooms in your key columns doesn&amp;rsquo;t mean you should fill it: remember impact to modifications, storage, memory, and maintenance&lt;/li&gt;
&lt;li&gt;Maximum key length for clustered indexes (B-Tree, Rowstore) is 900 bytes&lt;/li&gt;
&lt;li&gt;Maximum key length for nonclustered indexes in SQL Server 2016 and Azure SQL Database is 1700 bytes, and that&amp;rsquo;s only for the columns you explicitly define in the index&lt;/li&gt;
&lt;li&gt;Maximum key length for nonclustered indexes in prior versions of SQL Server is 900 bytes, and that&amp;rsquo;s only for the columns you explicitly define in the index&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s not too late to sign up for a full day of index training from me in Seattle this fall!&lt;/p&gt;</description></item><item><title>Collect and Baseline Wait Statistics (Dear SQL DBA Episode 14)</title><link>https://kendralittle.com/2016/08/25/collect-and-baseline-wait-statistics-dear-sql-dba-episode-14/</link><pubDate>Thu, 25 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/25/collect-and-baseline-wait-statistics-dear-sql-dba-episode-14/</guid><description>&lt;p&gt;What are the best tools to collect and baseline wait statistics? Should you write your own? Watch the 18 minute video or read the episode transcript below.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;Prefer a podcast&lt;/a&gt;?&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/QAoPcgpB8Xc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id="dear-sql-dba"&gt;Dear SQL DBA&amp;hellip;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I am getting into performance troubleshooting on SQL Server. I hear you talk about wait stats a lot, and how important they are to the process of troubleshooting.&lt;/p&gt;
&lt;p&gt;What ways are there to check the wait stats for a given time? How would you go about creating a baseline for a system you have just taken over?&lt;/p&gt;
&lt;p&gt;Sincerely,&lt;/p&gt;
&lt;p&gt;Waiting on Stats&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="i-do-love-wait-stats"&gt;I do love wait stats!&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Not-Napping-Collecting-Wait-Stats.png"
alt="Not-Napping-Collecting-Wait-Stats" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;If you listened to the performance tuning methodology I outlined in an earlier episode, you saw how important I think wait stats are for troubleshooting performance.&lt;/p&gt;
&lt;p&gt;If you missed that episode, it&amp;rsquo;s called &lt;a href="https://kendralittle.com/2016/06/02/dear-sql-dba-lost-in-performance-troubleshooting/"&gt;Lost in Performance Tuning&lt;/a&gt;. (I&amp;rsquo;ve got an outline of the discussion in the blog post, as always.)&lt;/p&gt;
&lt;h2 id="if-im-going-to-manage-the-system-for-a-long-time-i-would-buy-a-vendor-tool-to-baseline-wait-stats"&gt;If I&amp;rsquo;m going to manage the system for a long time, I would buy a vendor tool to baseline wait stats&lt;/h2&gt;
&lt;p&gt;SQL Server is a mature database. There&amp;rsquo;s a lot of vendors out there who have tapped into the need to track and baseline wait stats.&lt;/p&gt;
&lt;p&gt;They&amp;rsquo;ve honed tools to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Collect the waitstats in a lightweight manner&lt;/li&gt;
&lt;li&gt;Store them in a repository and groom the data over time, so it doesn&amp;rsquo;t explode&lt;/li&gt;
&lt;li&gt;Build reports for you to see big picture data&lt;/li&gt;
&lt;li&gt;Build fancy UIs for you to zoom in on a point in time&lt;/li&gt;
&lt;li&gt;Find queries that were running when the waits were occurring&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example vendors - I&amp;rsquo;m listing three that I&amp;rsquo;ve used before to solve problems:&lt;/p&gt;
&lt;p&gt;SQL Sentry Performance Advisor, Idera Diagnostic Manager, Dell Software (formerly Quest) Spotlight on SQL Server Enterprise&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t listed these in order of preference. I know people who swear by each of them.&lt;/p&gt;
&lt;p&gt;Since monitoring systems for SQL Server are pretty mature, the differences are in the details.&lt;/p&gt;
&lt;p&gt;Details can be very important, of course&amp;ndash; research and trials will help you find which one is the best fit for your team, processes, and applications.&lt;/p&gt;
&lt;h2 id="should-dbas-write-their-own-tools"&gt;Should DBAs write their own tools?&lt;/h2&gt;
&lt;p&gt;There are some people out there who think you should roll your own tools. That it makes you more legitimate.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve written a lot of my own tools. It takes a &lt;em&gt;lot&lt;/em&gt; of time.&lt;/p&gt;
&lt;p&gt;To get feature parity with what vendors are offering, we&amp;rsquo;re talking years of investment.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really easy to negatively impact performance with your tools. Tool vendors work very hard to avoid this, and it even happens to them sometimes.&lt;/p&gt;
&lt;p&gt;The difference is that the vendor has a bunch of engineers who can quickly fix the issue and release a new version.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s only worth it to write your own tools when nobody offers a solution that fits you.&lt;/p&gt;
&lt;h2 id="its-a-little-bit-likemonitoring-your-heart-rate-for-your-own-health"&gt;It&amp;rsquo;s a little bit like monitoring your heart rate for your own health&lt;/h2&gt;
&lt;p&gt;I wear a heart rate monitor to help me estimate how active I am during the day, and how hard I work during my workouts. Heart rate monitors are pretty affordable, and you can choose between wearing them on your wrist and wearing a chest strap. Some are more accurate than others, and they have different reporting tools.&lt;/p&gt;
&lt;p&gt;I could learn to take my own heart rate and sample and record it myself. I could probably build some reports off it. But I&amp;rsquo;m really happy having spent $150 for a device that does it for me.&lt;/p&gt;
&lt;p&gt;This leaves me free to spend my time interpreting the heart rate and calorie burn data it gives me, and customizing my activity to fit my health plan.&lt;/p&gt;
&lt;h2 id="how-to-get-budget-for-a-performance-monitoring-tool"&gt;How to get budget for a performance monitoring tool&lt;/h2&gt;
&lt;p&gt;Do two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Outline the business cases that a performance monitoring tool will help with. Link to specific customer incidents that it would help resolve.&lt;/li&gt;
&lt;li&gt;Pick the top 2 or 3 vendor tools you&amp;rsquo;d like to test, and map their features to the business cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bam, your request is looking a lot more legitimate.&lt;/p&gt;
&lt;h2 id="test-them-one-at-a-time-start-with-a-non-production-server"&gt;Test them one at a time. Start with a non-production server.&lt;/h2&gt;
&lt;p&gt;Your best bet is to write some code to reproduce performance problems against that server.&lt;/p&gt;
&lt;p&gt;Ideally these map to your business cases.&lt;/p&gt;
&lt;p&gt;Other ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find sample code with searches to simulate blocking and deadlocks, if you&amp;rsquo;d like to start there.&lt;/li&gt;
&lt;li&gt;Modify my sample code for testing inserts for race conditions with Microsoft&amp;rsquo;s free ostress tool for more fun (&lt;a href="https://kendralittle.com/2016/05/31/testing-an-insert-for-race-conditions-with-ostress-exe/"&gt;here it is&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Write some queries that read a lot of data and possibly run them from an Agent job (maybe it calls ostress)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review how your use cases all look in the tool you&amp;rsquo;re testing.&lt;/p&gt;
&lt;p&gt;Are the wait stats recorded and displayed well? Are they useful to you?&lt;/p&gt;
&lt;p&gt;How easy is it for you to find the queries related to the wait stats?&lt;/p&gt;
&lt;p&gt;Reach out to the vendor during your trial if you&amp;rsquo;re having problem. Sometimes the tools are smart in ways that aren&amp;rsquo;t obvious. This also gives you some insight into their support processes.&lt;/p&gt;
&lt;p&gt;Tip: check if the tool which you test sends monitoring data to the cloud. If so, make sure you get that approved by management before putting the tools into production. In sensitive environments, get that approved before you test it, too.&lt;/p&gt;
&lt;h2 id="if-im-troubleshooting-a-system-for-a-short-time-or-if-theres-no-budget-ill-use-and-contribute-to-an-open-source-tool"&gt;If I&amp;rsquo;m troubleshooting a system for a short time, or if there&amp;rsquo;s no budget, I&amp;rsquo;ll use and contribute to an open source tool&lt;/h2&gt;
&lt;p&gt;Sometimes there&amp;rsquo;s good reasons for budgetary limitations&amp;ndash; maybe you work for a non-profit and that money is literally feeding children.&lt;/p&gt;
&lt;p&gt;Or maybe you&amp;rsquo;re doing a short term analysis and you just need to collect information over a couple of days, and there&amp;rsquo;s no time to test and deploy a more robust tool.&lt;/p&gt;
&lt;p&gt;In that case, I&amp;rsquo;d start with &lt;a href="https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit"&gt;sp_BlitzFirst from Brent Ozar Unlimited&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s free&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s open source&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s got some documentation to get you started&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s already wired up to support different sample lengths, and write to tables&lt;/li&gt;
&lt;li&gt;It looks at running queries as well as some system metrics to help point out critical information related to the wait stats&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can start with what others have built, and slowly contribute on your own as well. Much nicer than starting from scratch.&lt;/p&gt;</description></item><item><title>Free Poster: tempdb data files in SQL Server</title><link>https://kendralittle.com/2016/08/23/free-poster-tempdb-data-files-in-sql-server/</link><pubDate>Tue, 23 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/23/free-poster-tempdb-data-files-in-sql-server/</guid><description>&lt;p&gt;The tempdb database is a strange place in SQL Server.&lt;/p&gt;
&lt;h2 id="about-this-poster"&gt;About This Poster&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/tempdb-data-files-small-preview.gif"
alt="tempdb-data-files-small-preview"&gt;
&lt;/figure&gt;
&lt;p&gt;This poster shows a view of the crazy world of tempdb and includes some reminders about tempdb configuration and monitoring.&lt;/p&gt;
&lt;p&gt;Someday I&amp;rsquo;ll publish my drawing bloopers of posters gone horribly wrong. Early versions of this one were hilariously horrifying. Moreso than the final product, I mean.&lt;/p&gt;
&lt;h2 id="more-posters"&gt;More Posters&lt;/h2&gt;
&lt;p&gt;Want more posters? &lt;a href="https://github.com/LitKnd/littlekendracomments/tree/main/SQLWorkbooks-Wallpaper-and-Posters"&gt;They now live on GitHub&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Developer Seeks DBA Career (Dear SQL DBA, Episode 13)</title><link>https://kendralittle.com/2016/08/18/developer-seeks-dba-career-dear-sql-dba-episode-13/</link><pubDate>Thu, 18 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/18/developer-seeks-dba-career-dear-sql-dba-episode-13/</guid><description>&lt;p&gt;A C# developer wants to be a DBA, but is having a hard time landing a job. Should they take a pay cut and go for a Junior level job? Or could there be another path?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Find the podcast version at&lt;/em&gt; &lt;a href="https://kendralittle.com/dearsqldba/"&gt;&lt;em&gt;kendralittle.com/dear-sql-dba-podcast&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A written version of the discussion with clickable links is just under this video.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/kNRZWOOF6yM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been a C# developer since year 2000. I want to move to be a DBA. I’ve started getting involved at user groups and SQL Saturdays but nobody wants to hire me as a DBA.&lt;/p&gt;
&lt;p&gt;I have been trying to move to other companies but my resume is strongly inclined to show my C#, front end experience. I know for a fact that I&amp;rsquo;m really good on SQL as I keep solving problems in every other project but no one seems to pay really attention to the DB. I have noticed that when applying for positions I get called for my C# experience but not when applying only to SQL jobs.&lt;/p&gt;
&lt;p&gt;Should I find a Junior DBA position and take a pay cut?&lt;/p&gt;
&lt;p&gt;Sincerely,&lt;/p&gt;
&lt;p&gt;Devloper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="this-isnt-an-easy-transition"&gt;This isn&amp;rsquo;t an easy transition&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Developer-Seeks-DBA-Job-300x300.png"
alt="Developer-Seeks-DBA-Job" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;DBAs out there: think about transitioning the other way, from DBA to C# developer. It&amp;rsquo;s not simple!&lt;/p&gt;
&lt;p&gt;Hiring managers look for direct experience.&lt;/p&gt;
&lt;h2 id="finding-a-junior-dba-position-isnt-an-easy-solution"&gt;Finding a Junior DBA position isn&amp;rsquo;t an easy solution&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not just the pay cut&amp;ndash; Junior DBA jobs are hard to find.&lt;/p&gt;
&lt;p&gt;Hiring managers are often wary of bringing in someone with senior experience in another area who is used to earning more. There&amp;rsquo;s a real risk that you&amp;rsquo;ll be dissatisfied with &amp;ldquo;the grunt work&amp;rdquo;, which you&amp;rsquo;ve outgrown in other areas. And doing the grunt work for less pay isn&amp;rsquo;t that easy to find joy in, either.&lt;/p&gt;
&lt;p&gt;The kind of experience people are looking for in Junior DBAs is also experience that&amp;rsquo;s far from your realm: backups, CHECKDB, that kind of thing.&lt;/p&gt;
&lt;p&gt;I recommend people starting as DBAs from scratch to start with a foundation of backups and build upward.&lt;/p&gt;
&lt;p&gt;I even have a &lt;a href="https://kendralittle.com/2016/03/29/training-plan-for-junior-dbas-learning-sql-server/"&gt;free training plan for Junior DBAs&lt;/a&gt; that can help you get those very basics. Those things are extremely valuable for you to know.&lt;/p&gt;
&lt;p&gt;But I don&amp;rsquo;t think you should &amp;ldquo;sell yourself&amp;rdquo; as a Junior DBA.&lt;/p&gt;
&lt;h2 id="set-your-target-job"&gt;Set your target job&lt;/h2&gt;
&lt;p&gt;The biggest question here is what type of DBA work you want to do. Do you want to be a DBA developer, or a pure DBA?&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a lot of options here because of the increasing popularity of DevOps, which emphasizes breadth of skills and excellence in multiple areas.&lt;/p&gt;
&lt;p&gt;Large database environments and cloud environments also mean that there are positions where people need to excel at using scripting and automation to manage environments.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PowerShell and c# are both very desirable skills for a DBA for automation and building dashboards.&lt;/li&gt;
&lt;li&gt;Knowledge of how to plan, stage, and deploy database code changes safely while limiting customer impact is also very desirable - this often involves scripting in building and managing code deployment tools.&lt;/li&gt;
&lt;li&gt;Experience building CLR components for SQL Server (and knowing where it shines and where to avoid it) is somewhat rare, but can be desirable for employers. This is more of a niche option, I wouldn&amp;rsquo;t  put &lt;em&gt;all&lt;/em&gt; your eggs in this basket, but it can be part of a great package if you have it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think about how your dream DBA job might still involve working with code. What&amp;rsquo;s the map look like between where you are and those skills?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s your special angle.&lt;/p&gt;
&lt;h2 id="write-aresumejust-for-yourtarget-job"&gt;Write a resume just for your target job&lt;/h2&gt;
&lt;p&gt;One thing that jumped out at me is that you said, &amp;ldquo;my resume is strongly inclined to show my C#&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Resumes aren&amp;rsquo;t everything. Honestly, networking is more important than resumes. But resumes still matter.&lt;/p&gt;
&lt;p&gt;You need more than one resume. It&amp;rsquo;s fine to have one that&amp;rsquo;s inclined to show your C#, but you need another &amp;ldquo;base&amp;rdquo; resume highlighting everything you&amp;rsquo;ve done that makes you a candidate for that target job.&lt;/p&gt;
&lt;p&gt;Your resume is just as much about &lt;em&gt;where you want to go&lt;/em&gt; as &lt;em&gt;what you&amp;rsquo;ve done&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying to lie on your resume. NOT AT ALL. That&amp;rsquo;s a huge no-no. You also don&amp;rsquo;t want to make your resume long. 2 pages is &amp;ldquo;long&amp;rdquo; for a technical resume these days.&lt;/p&gt;
&lt;p&gt;Writing a resume is the same thing as telling a short story about your life. Focus your short story on the things you&amp;rsquo;ve done with SQL Server.&lt;/p&gt;
&lt;p&gt;You mention that you do have some chances to solve problems with SQL. That&amp;rsquo;s awesome! There needs to be a version of your resume that highlights those problems you&amp;rsquo;ve solved.&lt;/p&gt;
&lt;p&gt;You also want to think about the skills needed for your target job, and highlight the skills you have which lead toward that job.&lt;/p&gt;
&lt;p&gt;At your career stage, this usually means leaving off other skills you have, which just aren&amp;rsquo;t relevant for that dream job. That&amp;rsquo;s normal. It&amp;rsquo;s also normal at your career stage to tweak and edit your resume for each job you apply to.&lt;/p&gt;
&lt;h2 id="adjust-your-networking-strategy-to-your-target-job"&gt;Adjust your networking strategy to your target job&lt;/h2&gt;
&lt;p&gt;Talk to multiple recruiters.&lt;/p&gt;
&lt;p&gt;I know, I know, some of them are slimy. But there are some good ones out there, so it&amp;rsquo;s worth working through them.&lt;/p&gt;
&lt;p&gt;Tell the recruiters about your target job. Ask them how they think you can get there.&lt;/p&gt;
&lt;p&gt;When you &lt;em&gt;do&lt;/em&gt; land an interview, try to get the email addresses for the folks who interview you. Send a thank you letter. If the job doesn&amp;rsquo;t work out, try sending an email asking for advice on how to improve.&lt;/p&gt;
&lt;p&gt;Tone matters a lot in this email. This isn&amp;rsquo;t about getting that job, it&amp;rsquo;s gone, and  you don&amp;rsquo;t want to sound bitter- you want to use language about helping yourself improve for the future.&lt;/p&gt;
&lt;p&gt;You won&amp;rsquo;t always get feedback, and that&amp;rsquo;s totally fine! But just the act of asking for it in a friendly, positive way may end up getting you referred for another job later on. It&amp;rsquo;s worth doing.&lt;/p&gt;
&lt;p&gt;Consider finding code camps and hackathons. Be &amp;ldquo;the database person&amp;rdquo;. Work your way into projects and meet people.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The projects can be great stories for your resume if they align with your target job&lt;/li&gt;
&lt;li&gt;The contacts may help you land a developer-DBA job&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you meet people who work in the types of groups you want to join, ask them about how their group works. Ask what experience people needed to join. If you have a rapport going, ask them if they&amp;rsquo;d be willing to do you a favor and review your resume afterward and give you feedback on where you might be able to improve, with the goal of joining a similar team.&lt;/p&gt;
&lt;h2 id="pulling-this-off-leads-you-to-a-unicorn-track"&gt;Pulling this off leads you to a &amp;lsquo;unicorn&amp;rsquo; track&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s natural that this has been tough for you, because it really is a hard transition.&lt;/p&gt;
&lt;p&gt;But although it&amp;rsquo;s tough, once you are able to make the transition, having skills as both a developer and developing database expertise can be a killer combination. If you get a job where you can keep working both sides of those skills, this gives you a unique insight into problem solving and managing environments.&lt;/p&gt;
&lt;p&gt;It can make you a unicorn. So while it&amp;rsquo;s tough, keep at it, and you&amp;rsquo;ll eventually find the right spot.&lt;/p&gt;</description></item><item><title>Does Adding NOINDEX Change DBCC CHECKDB with PHYSICAL_ONLY?</title><link>https://kendralittle.com/2016/08/16/does-adding-noindex-change-dbcc-checkdb-with-physical_only/</link><pubDate>Tue, 16 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/16/does-adding-noindex-change-dbcc-checkdb-with-physical_only/</guid><description>&lt;p&gt;The NOINDEX option &lt;em&gt;does&lt;/em&gt; change the behavior of DBCC CHECKDB (even if you&amp;rsquo;re already using PHYSICAL_ONLY). Here&amp;rsquo;s how the two options compare to one another, and how to see the difference yourself in a simple example.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Turn-your-keyboard-300x300.png"
alt="Turn your keyboard" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;This question came up on &lt;a href="https://twitter.com/jasonhorner/status/765173929006641153"&gt;Twitter&amp;rsquo;s #sqlhelp recently&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="physical_only-is-like-having-a-doctor-examineyour-body-but-not-runbloodwork"&gt;PHYSICAL_ONLY is like having a doctor examine your body, but not run bloodwork&lt;/h2&gt;
&lt;p&gt;PHYSICAL_ONLY looks at page structures and makes sure something isn&amp;rsquo;t obviously wrong. If you have the database&amp;rsquo;s page verification option set to CHECKSUM (the default since SQL Server 2005, and &lt;a href="https://kendralittle.com/2011/01/25/pageverify/"&gt;a very good thing&lt;/a&gt;), it runs a checksum on the page and compares it to a checksum recorded in the header when the page was last modified.&lt;/p&gt;
&lt;p&gt;When you use the PHYSICAL_ONLY option, you&amp;rsquo;re telling SQL Server to skip logical checks. It won&amp;rsquo;t do things like make sure the data in a clustered and nonclustered index on a table is consistent with one another.&lt;/p&gt;
&lt;h2 id="noindex-is-like-telling-the-doctor-to-ignoresome-body-parts-altogether"&gt;NOINDEX is like telling the doctor to ignore some body parts altogether&lt;/h2&gt;
&lt;p&gt;NOINDEX tells SQL Server to skip nonclustered indexes on your user tables. It just ignores them.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s not obvious from the documentation is that it&amp;rsquo;s not just skipping the logical checks, it&amp;rsquo;s skipping the physical checks as well for nonclustered indexes on user tables. It won&amp;rsquo;t look at those handy checksums at all!&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know about you, but I&amp;rsquo;d rather the doctor mention to me if my pinky finger is on fire, whether or not I can live without it.&lt;/p&gt;
&lt;h2 id="prove-it-corrupt-a-nonclustered-index-and-then-run-checkdb-three-ways"&gt;Prove it! Corrupt a nonclustered index and then run CHECKDB three ways.&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s simple to corrupt a nonclustered index in a database with a free Hex Editor. Here&amp;rsquo;s a post I wrote in 2011 with &lt;a href="https://kendralittle.com/2011/01/24/corrupthexeditor/"&gt;steps on how to corrupt a nonclustered index&lt;/a&gt;. The same steps still work just fine on SQL Server 2016.&lt;/p&gt;
&lt;p&gt;After you have your corrupt nonclustered index, test these three commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DBCC CHECKDB (CorruptMe) with PHYSICAL_ONLY;
&lt;ul&gt;
&lt;li&gt;This will find the corruption - it sees the checksum mismatch on the physical page of the nonclustered index.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DBCC CHECKDB (CorruptMe, NOINDEX) with PHYSICAL_ONLY;
&lt;ul&gt;
&lt;li&gt;This will not find the corruption, NOINDEX tells it to skip the nonclustered index altogether.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DBCC CHECKDB (CorruptMe, NOINDEX);
&lt;ul&gt;
&lt;li&gt;This will also not find the corruption because NOINDEX tells it to skip the nonclustered index altogether.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Teach Yourself SQL Server Performance Tuning (Dear SQL DBA Episode 12)</title><link>https://kendralittle.com/2016/08/11/teach-yourself-sql-server-performance-tuning-dear-sql-dba-episode-12/</link><pubDate>Thu, 11 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/11/teach-yourself-sql-server-performance-tuning-dear-sql-dba-episode-12/</guid><description>&lt;p&gt;You&amp;rsquo;d love to have a job tuning SQL Servers, but you don&amp;rsquo;t have an environment to practice in. Here&amp;rsquo;s how to teach yourself performance tuning and prepare yourself to land and succeed in job interviews.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is a “listen-able” 20 minute video. Prefer a podcast instead? Find it at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dearsqldba&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A written version of the discussion with clickable links is just under this video.&lt;/strong&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/6zAt-hUxRAY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there a way I can gain SQL performance tuning experience if I don&amp;rsquo;t have access to a live production environment? I read lots of blogs and attend classes and conferences were I can, but I don&amp;rsquo;t feel confident.&lt;/p&gt;
&lt;p&gt;I know real experience is the best, but I’d like to do whatever I can, and I&amp;rsquo;d like to get a job tuning performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="youre-right-to-ask-this-question-job-interviews-focus-heavily-onexperience"&gt;You&amp;rsquo;re right to ask this question: job interviews focus heavily on experience&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s tough to get a job without direct experience.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s a bright side with performance tuning: not a lot of people &lt;em&gt;have&lt;/em&gt; direct experience.&lt;/p&gt;
&lt;p&gt;If you follow what I outline in this post,  you&amp;rsquo;ll be able to talk about what you&amp;rsquo;ve done to learn and the problems you&amp;rsquo;ve retro-engineered and solved. That will give you a real advantage in those interviews.&lt;/p&gt;
&lt;h2 id="youre-going-to-need-asample-dataset-to-work-with"&gt;You&amp;rsquo;re going to need a sample dataset to work with&lt;/h2&gt;
&lt;p&gt;There are lots of options for sample databases. Anything can work.&lt;/p&gt;
&lt;p&gt;With any dataset, you may need to write code to enlarge tables or change the data around to demonstrate specific problems. That&amp;rsquo;s a normal part of the challenge &amp;ndash; it&amp;rsquo;s really a feature in a way.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s just a few of the sample databases out there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft&amp;rsquo;s AdventureWorks sample database: &lt;a href="http://msftdbprodsamples.codeplex.com/"&gt;http://msftdbprodsamples.codeplex.com/&lt;/a&gt;. AdventureWorks is small. To demonstrate slow queries and speed them up, expanding the database is very helpful.  Jonathan Kehayias &lt;a href="https://www.sqlskills.com/blogs/jonathan/enlarging-the-adventureworks-sample-databases/"&gt;wrote a script to enlarge it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Microsoft&amp;rsquo;s &lt;a href="https://blogs.technet.microsoft.com/dataplatforminsider/2016/06/09/wideworldimporters-the-new-sql-server-sample-database/"&gt;World Wide Importers sample database for SQL Server 2016&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/LitKnd/BabbyNames/releases/tag/v1.1"&gt;BabbyNames sample database - large or small options&lt;/a&gt;. I&amp;rsquo;m biased towards this one because I maintain it on GitHub.&lt;/li&gt;
&lt;li&gt;StackOverflow sample database, &lt;a href="https://www.brentozar.com/archive/2015/10/how-to-download-the-stack-overflow-database-via-bittorrent/"&gt;shared on BitTorrent by Brent Ozar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sqlskills.com/sql-server-resources/sql-server-demos/"&gt;SQLSkills sample databases&lt;/a&gt;, including their Credit database, SalesDB, and a Baseball Stats database.&lt;/li&gt;
&lt;li&gt;There are also &lt;a href="https://kendralittle.com/2015/12/15/free-open-license-datasets-at-data-gov/"&gt;many free data downloads at Data.gov&lt;/a&gt;, if you want to build your own!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have enough space to keep multiple of these databases on your instance, there&amp;rsquo;s no reason to only use one of them as a learner.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re planning to take your experience and teach a class, you may want to focus on just one sample database, though &amp;ndash; and also make sure you have the rights to share it with students. (Switching around between databases in a class can be confusing.)&lt;/p&gt;
&lt;h2 id="start-writing-queries-that-demonstrate-tsql-anti-patterns---and-make-them-slow"&gt;Start writing queries that demonstrate TSQL anti patterns - and make them slow&lt;/h2&gt;
&lt;p&gt;You know how people say that the best way to learn something is to teach it?&lt;/p&gt;
&lt;p&gt;The best way to learn to speed up queries is to write slow ones.&lt;/p&gt;
&lt;p&gt;The best way to get a job speeding up queries is to write a blog about the queries you&amp;rsquo;ve sped up.&lt;/p&gt;
&lt;p&gt;The hardest part is going to be writing slow queries properly. You wouldn&amp;rsquo;t think that it takes talent to write truly crappy TSQL, but it takes me quite a long time to write terrible queries that demonstrate an anti-pattern against a sample dataset.&lt;/p&gt;
&lt;p&gt;Two articles will get you started on anti-patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grant Fritchey&amp;rsquo;s &lt;a href="https://www.simple-talk.com/sql/performance/the-seven-sins-against-tsql-performance/"&gt;Seven Sins against TSQL Performance&lt;/a&gt; article on Simple Talk&lt;/li&gt;
&lt;li&gt;Aaron Bertrand&amp;rsquo;s &lt;a href="http://blogs.sqlsentry.com/aaronbertrand/bad-habits-revival/#index"&gt;Bad Habits Revival&lt;/a&gt; on the SQL Sentry blog (not all cause performance issues, you&amp;rsquo;ll learn as you work through the list)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These articles will include sample code. Use that as inspiration.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you really want to learn performance tuning outside of a production environment, writing your own slow code and then speeding it up is the most effective approach.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="for-each-anti-pattern-you-create-understand-the-execution-plan-and-how-to-measure-the-query"&gt;For each anti pattern you create, understand the execution plan and how to measure the query&lt;/h2&gt;
&lt;p&gt;For each slow query you write, test different solutions and compare them. To do this well, you&amp;rsquo;ll need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Research operators in the execution plans when the query is slow and fast&lt;/li&gt;
&lt;li&gt;Learn how to measure performance using tools like STATISTICS TIME and STATISTICS IO&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I find that the easiest way to do this is to make lots of notes in my TSQL scripts as I go, to remind myself of the performance at different points in the script.&lt;/p&gt;
&lt;h2 id="use-the-queries-to-make-an-anti-pattern-environment"&gt;Use the queries to make an anti-pattern environment&lt;/h2&gt;
&lt;p&gt;Once you have a bunch of slow queries, you can create an environment of bad queries.&lt;/p&gt;
&lt;p&gt;One easy way to do this is to set up SQL Server Agent jobs that run the queries in a loop or on a scheduled basis.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll learn quickly that you do have to meter them out in a way, because just running a ton of stuff in a tight loop is going to completely overwhelm your CPUs.&lt;/p&gt;
&lt;p&gt;Some options for running a bunch of queries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Michael J Swart wrote a great post on &lt;a href="http://michaeljswart.com/2014/01/generating-concurrent-activity/"&gt;generating concurrent activity&lt;/a&gt; that lists out a bunch of tools which can help.&lt;/li&gt;
&lt;li&gt;One note is that the &lt;a href="https://github.com/ErikEJ/SqlQueryStress"&gt;SQL Query Stress&lt;/a&gt; tool originally written by Adam Machanic is now maintained on GitHub by Erik, Ejlskov Jensen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="practice-finding-the-worst-queries-and-diagnosing-a-solution"&gt;Practice finding the worst queries and diagnosing a solution&lt;/h2&gt;
&lt;p&gt;Some of your bad queries are going to be worse for your instance than others.&lt;/p&gt;
&lt;p&gt;But which are the worst of the worst?&lt;/p&gt;
&lt;p&gt;And what&amp;rsquo;s the most efficient way to fix the top three queries with the least amount of work?&lt;/p&gt;
&lt;p&gt;After automating your queries, you can now practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using sp_WhoIsActive to find out what&amp;rsquo;s slow right now&lt;/li&gt;
&lt;li&gt;using wait statistics to measure bottlenecks on the instance (&lt;a href="https://kendralittle.com/2016/06/02/dear-sql-dba-lost-in-performance-troubleshooting/"&gt;see the episode on my performance tuning process&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="finally-add-in-database-and-server-level-anti-patterns"&gt;Finally, add in database and server level anti-patterns&lt;/h2&gt;
&lt;p&gt;You can take this even farther, and challenge yourself to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simulate tempdb contention&lt;/li&gt;
&lt;li&gt;Turn on database auto-shrink, and see if you can identify from the server exactly what it slows down and by how much&lt;/li&gt;
&lt;li&gt;Change server settings related to parallelism and measure how  it impacts performance, and how you would detect and tune those settings. (I did an episode on parallelism called &lt;a href="https://kendralittle.com/2016/07/14/max-degree-of-parallelism-cost-threshold-for-parallelism/"&gt;Max Degree of Confusion&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;Lower your memory settings so not all data fits in cache, and measure how that impacts performance&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="remember-what-i-said-about-the-blog"&gt;Remember what I said about the blog?&lt;/h2&gt;
&lt;p&gt;Blogging about this process as you go through it serves a few purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Writing about it helps you remember things&lt;/li&gt;
&lt;li&gt;Writing about it under your name will act as an online resume&lt;/li&gt;
&lt;li&gt;Bonus: you&amp;rsquo;re helping others as you go&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;re going to need to be persistent about this project to make it work. And it&amp;rsquo;s going to take a lot of time.&lt;/p&gt;
&lt;p&gt;Blogging as you go is extra work, but if your goal is to get a job, it&amp;rsquo;s incredibly valuable - because if you do this once a week for a year, that link at the top of your resume is going to be almost as awesome as your confidence about what you&amp;rsquo;ve learned.&lt;/p&gt;</description></item><item><title>SSMS Tips: Templates and Control+Shift+M</title><link>https://kendralittle.com/2016/08/09/ssms-tips-templates-and-controlshiftm/</link><pubDate>Tue, 09 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/09/ssms-tips-templates-and-controlshiftm/</guid><description>&lt;p&gt;Templates are extremely handy for tasks that you need to do repeatedly, but with different parameter values. The coolest part is that once you get the hang of them, you can &lt;a href="https://msdn.microsoft.com/en-us/library/ms166841.aspx"&gt;create your own custom templates&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="important-reminder"&gt;Important Reminder&lt;/h2&gt;
&lt;p&gt;Whether or not you&amp;rsquo;re using a template, &lt;em&gt;always make sure that you&amp;rsquo;re connected to the right server before you hit execute&lt;/em&gt;. Don&amp;rsquo;t ask me how I know to mention that reminder ;)&lt;/p&gt;
&lt;h2 id="using-templates"&gt;Using Templates&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a demo of how to use a simple template. Use the keyboard shortcut Control+Shift+M to open the template parameter editor.&lt;/p&gt;
&lt;p&gt;The mnemonic I use to remember the shortcut is &amp;ldquo;Control and Shift &lt;strong&gt;M&lt;/strong&gt;icrosoft!&amp;rdquo;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://media.giphy.com/media/WjJEvFRruQ9t4cLkjh/source.gif"
alt="Template-Demo"&gt;
&lt;/figure&gt;</description></item><item><title>Altering an INT Column to a BIGINT (Dear SQL DBA Episode 11)</title><link>https://kendralittle.com/2016/08/04/altering-an-int-column-to-a-bigint-dear-sql-dba-episode-11/</link><pubDate>Thu, 04 Aug 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/08/04/altering-an-int-column-to-a-bigint-dear-sql-dba-episode-11/</guid><description>&lt;p&gt;You need to change an INT column to a BIGINT in a large table. Learn why this schema change can make your transaction log explode, and how to avoid it.&lt;/p&gt;
&lt;p&gt;Prefer a podcast instead? Find it at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dear-sql-dba-podcast&lt;/a&gt;.__&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Show notes (transcript with links) are below the video.&lt;/strong&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/sCoLRRsjM6o?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="heres-our-question-for-the-week"&gt;Here&amp;rsquo;s our question for the week&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;I have a 120GB table with 2 billion records and the Clustered Primary Key is an INT column. What&amp;rsquo;s the best way (and fastest) to convert this INT to a BIG INT?&lt;/p&gt;
&lt;p&gt;The database is in the full recovery model, and I can take downtime up to a day on the weekend.&lt;/p&gt;
&lt;p&gt;With Concern,&lt;/p&gt;
&lt;p&gt;Billions and Billions Served&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="what-happens-when-you-run-out-of-ints"&gt;What happens when you run out of INTs?&lt;/h2&gt;
&lt;p&gt;The integer data type in SQL Server allows numbers up to 2.147 billion rows (with a little change).&lt;/p&gt;
&lt;p&gt;If you try to insert a row with a value above that, it fails with error 8115:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Msg 8115, Level 16, State 1, Line 142&lt;/p&gt;
&lt;p&gt;Arithmetic overflow error converting IDENTITY to data type int.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At that point, you have to do &lt;em&gt;something&lt;/em&gt; to insert more rows.&lt;/p&gt;
&lt;h2 id="altering-the-data-type-of-the-column-is-a-size-of-data-operation"&gt;Altering the data type of the column is a &amp;ldquo;size of data&amp;rdquo; operation&lt;/h2&gt;
&lt;p&gt;This seems straightforward at first. Let&amp;rsquo;s change the column to a bigint!&lt;/p&gt;
&lt;p&gt;The first thing you notice is that you&amp;rsquo;re going to have to remove the Clustered Primary Key. You can&amp;rsquo;t change a data type with that there.&lt;/p&gt;
&lt;p&gt;So we&amp;rsquo;re already in outage territory (even before you think about whether or not you have foreign keys defined against this PK or replication on the table).&lt;/p&gt;
&lt;p&gt;Once you get to the point where you can alter the data, you run into a different problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Altering the column uses a huge amount of transaction log space&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s reaaaalllll slow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is because changing from INT to BIGINT is a &amp;ldquo;size-of-data&amp;rdquo; operation.&lt;/p&gt;
&lt;p&gt;SQL Server has to go through and update Every. Single. Row.&lt;/p&gt;
&lt;p&gt;And log it.&lt;/p&gt;
&lt;p&gt;And SQL Server has to reserve extra space in the log in case it needs to roll back (because that will require additional logging).&lt;/p&gt;
&lt;p&gt;If you get this far without thinking about how much log file you&amp;rsquo;re going to need and you run out, then things get extra slow, because most of that rollback&amp;rsquo;s going to be done by just one thread.&lt;/p&gt;
&lt;h2 id="you-can-choose-to-reseed-an-identity-column"&gt;You can choose to &amp;ldquo;reseed&amp;rdquo; an identity column&lt;/h2&gt;
&lt;p&gt;The integer data type can support down to -2.147 billion rows (and some change).&lt;/p&gt;
&lt;p&gt;You can reset your identity column to -1 and work your way backwards by negative increments.&lt;/p&gt;
&lt;p&gt;You can reset your identity all the way to the lowest possible value and work your way back towards zero.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The good news&lt;/strong&gt;: it&amp;rsquo;s fast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The bad news&lt;/strong&gt;: I have never met a Change Approver who loves this option. It makes them very itchy and uncomfortable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reseeding an identity column like duct tape: it&amp;rsquo;s a temporary solution, and you&amp;rsquo;re going to have to fix it for real later. And it&amp;rsquo;s unfamiliar duct tape.&lt;/p&gt;
&lt;p&gt;Who looks at a brand of off brand duct tape and wants to use it to repair their roof?&lt;/p&gt;
&lt;p&gt;If you do reseed to get things moving right away, the table just gets bigger, and the job of fixing it gets incrementally harder as time moves on.&lt;/p&gt;
&lt;h2 id="inserting-the-data-into-a-new-table-is-usuallyfaster-than-altering-the-column-for-large-tables-particularly-if-you-can-get-minimal-logging"&gt;Inserting the data into a new table is usually faster than altering the column for large tables, particularly if you can get minimal logging&lt;/h2&gt;
&lt;p&gt;This is pretty simple if you can take an outage. During the outage:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new table using the new data type&lt;/li&gt;
&lt;li&gt;Set identity_insert on for the new table if you have an identity&lt;/li&gt;
&lt;li&gt;Insert all the rows with tricks to minimize transaction log use&lt;/li&gt;
&lt;li&gt;Create all the indexes, constraints, etc to make it identical&lt;/li&gt;
&lt;li&gt;If it&amp;rsquo;s an identity column, don&amp;rsquo;t forget to fix that up so new inserts generate a new identity&lt;/li&gt;
&lt;li&gt;Use renames or schema transfer to make the new table active&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do test this against a restored backup first so you can make sure you have all the details right and know how much data log and transaction log space you&amp;rsquo;re going to need. The work with all the indexes can still require substantial log usage.&lt;/p&gt;
&lt;h2 id="how-to-minimize-logging"&gt;How to minimize logging&lt;/h2&gt;
&lt;p&gt;SQL Server can do &amp;ldquo;minimal logging&amp;rdquo; in the Simple or Bulk Logged recovery model. NOT in the full recovery model. If your database is in the Full recovery model, you&amp;rsquo;re going to have to spend some time thinking about recovery models and backups.&lt;/p&gt;
&lt;p&gt;With Bulk Logged recovery model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are going to have a very large and possibly very slow log backup if you do a lot of bulk changes&lt;/li&gt;
&lt;li&gt;You lose point-in-time recovery for any log backup that contains bulk logged changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With Simple Recovery model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changing to this breaks your transaction log backup chain&lt;/li&gt;
&lt;li&gt;You can restart the transaction log backup chain with either a full or differential backup after the change has done (but again, you&amp;rsquo;re making a lot of changes so that differential might be pretty slow, depending)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your database is already in the Simple recovery model, then party, it&amp;rsquo;s easier. Just make sure you don&amp;rsquo;t try to get minimal logging while a backup is running, that doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;The next step is to read the &amp;ldquo;Understanding Minimal Logged Operations&amp;rdquo; in the &lt;a href="https://technet.microsoft.com/en-us/library/dd425070(v=sql.100).aspx"&gt;Data Loading Performance Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re inserting rows into a heap with no nonclustered indexes, typically you can get minimal logging by just using a TABLOCK hint.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re inserting rows into an empty table with a clustered index, you may need additional hints or Trace Flag 610 on your statement.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a handy dandy table in the whitepaper to make it easy.&lt;/p&gt;
&lt;p&gt;Typically inserting into a heap with no indexes is the fastest option. If the speed of the change is important, test different inserts.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using SQL Server 2005, well, first it&amp;rsquo;s out of support. Second, it doesn&amp;rsquo;t allow minimal logging for INSERT SELECT operations, you have to do some SELECT FROM OPENROWSET (BULK ) weirdness.&lt;/p&gt;
&lt;h2 id="what-if-you-cant-take-the-long-downtime"&gt;What if you can&amp;rsquo;t take the long downtime?&lt;/h2&gt;
&lt;p&gt;Sometimes you just can&amp;rsquo;t take the outage. In that case, you&amp;rsquo;ve got to proceed with your own wits, and your own code. This is tricky because changes are occurring to the table.&lt;/p&gt;
&lt;p&gt;The solution typically looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set up a way to track changes to the table - either triggers that duplicate off modifications or Change Data Capture (Enterprise Edition)&lt;/li&gt;
&lt;li&gt;Create the new table with the new data type, set identity_insert on if needed&lt;/li&gt;
&lt;li&gt;Insert data into the new table. This is typically done in small batches, so that you don&amp;rsquo;t overwhelm the log or impact performance too much. You may use a snapshot from the point at which you started tracking changes.&lt;/li&gt;
&lt;li&gt;Start applying changed data to the new table&lt;/li&gt;
&lt;li&gt;Make sure you&amp;rsquo;re cleaning up from the changed data you&amp;rsquo;re catching and not running out of space&lt;/li&gt;
&lt;li&gt;Write scripts to compare data between the old and new tables to make sure you&amp;rsquo;re really in sync (possibly use a snapshot or a restored backup to compare a still point in time)&lt;/li&gt;
&lt;li&gt;Cut over in a quick downtime at some point using renames, schema transfer, etc. If it&amp;rsquo;s an identity column, don&amp;rsquo;t forget to fix that up properly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="multi-terabyte-example"&gt;Multi-Terabyte example&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve worked with cases of Extra Extra Large databases where schema changes were staged outside of production using SAN snapshots and new databases.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve got an XXL change, SAN magic can be a big help.&lt;/p&gt;
&lt;h2 id="aside-sql-server-2012-added-a-new-enterprise-feature-to-eliminate-one-type-ofsize-of-data-operation"&gt;Aside: SQL Server 2012 added a new Enterprise feature to eliminate one type of size of data operation&lt;/h2&gt;
&lt;p&gt;SQL Server 2012 added a feature where adding a new non-nullable column with default values is no longer a size of data operation.&lt;/p&gt;
&lt;p&gt;This is an Enterprise Edition feature and it only works for non LOB types (no nvarchar(max), XML, etc). It&amp;rsquo;s also picky about rowsize.&lt;/p&gt;
&lt;p&gt;Remus Rusanu wrote about this feature here in his article &lt;a href="http://rusanu.com/2011/07/13/online-non-null-with-values-column-add-in-sql-server-11/"&gt;Online non-NULL with values column add in SQL Server 2012&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This doesn&amp;rsquo;t help our case here, because our existing Primary Key isn&amp;rsquo;t the same as a &amp;ldquo;default value&amp;rdquo;. But it might help some readers.&lt;/p&gt;
&lt;h2 id="want-more-takes-on-this-problem"&gt;Want more takes on this problem?&lt;/h2&gt;
&lt;p&gt;Aaron Bertrand has written a very detailed four part series with sample code. &lt;a href="http://sqlperformance.com/2016/01/sql-indexes/widening-identity-column-1"&gt;Start here to read the first article&lt;/a&gt;. (Links to the next three are at the bottom of the post.)&lt;/p&gt;
&lt;p&gt;Kenneth Fisher wrote a great post about his experience with altering a column in a 750GB table in his article - &lt;a href="https://sqlstudies.com/2016/07/14/altering-a-column-in-a-large-table-a-case-study/"&gt;Altering a column in a large table: a case study&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to know more about how altering columns works internally, check out Remus Rusanu&amp;rsquo;s article, &lt;a href="http://rusanu.com/2011/10/20/sql-server-table-columns-under-the-hood/"&gt;SQL Server table columns under the hood&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Should I Automate my Windows Updates for SQL Server? (Dear SQL DBA Episode 10)</title><link>https://kendralittle.com/2016/07/28/should-i-automate-my-windows-updates-for-sql-server-dear-sql-dba-episode-10/</link><pubDate>Thu, 28 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/28/should-i-automate-my-windows-updates-for-sql-server-dear-sql-dba-episode-10/</guid><description>&lt;p&gt;Your boss wants you to automate patching for your SQL Servers. Is that a good idea? How far should you take it? Find out a DBAs perspective.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been tasked with getting a patching solution for our SQL servers that doesn&amp;rsquo;t require us to sit and watch the installer.&lt;/p&gt;
&lt;p&gt;The installer provides a lot of good feedback, and the patch is going to take as long as it takes no matter what. If I don&amp;rsquo;t watch the installer (ie, I run the patch from a command line with /quiet /action=Patch, etc), I&amp;rsquo;m still going to have to review the summary.txt file for feedback on the patch success, etc.&lt;/p&gt;
&lt;p&gt;Would you recommend cobbling together a command line/scheduled task scheme and hope it all goes fine with manual reviews of the txt/log files after the fact?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Show notes (transcript with links) are below the video.&lt;/strong&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/qoQbTG8jJhA?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="im-just-as-lazy-as-any-other-dba-actually-im-more-lazy"&gt;I&amp;rsquo;m just as lazy as any other DBA.  Actually, I&amp;rsquo;m more lazy.&lt;/h2&gt;
&lt;p&gt;Patching isn&amp;rsquo;t fun work, but it&amp;rsquo;s really necessary. Organizations that don&amp;rsquo;t regularly apply Windows patches run the risk of security breaches and weird performance problems.&lt;/p&gt;
&lt;p&gt;It involves a lot of waiting, it&amp;rsquo;s pretty boring, and it usually happens at a time where you&amp;rsquo;d rather be doing something else - like Friday night or Sunday morning.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m generally in favor of anything that makes patching less work. I don&amp;rsquo;t want it to introduce unacceptable risks for the data, based on business requirements, but I love &lt;em&gt;smart&lt;/em&gt; automation that can help me do more, faster, and be safer.&lt;/p&gt;
&lt;h2 id="it-stinkswhen-patching-goes-wrong"&gt;It stinks when patching goes wrong&lt;/h2&gt;
&lt;p&gt;I used to spend a lot of time doing patching, and I had plenty of times when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Servers wouldn&amp;rsquo;t come back up after a reboot&lt;/strong&gt;. Someone had to go into the iLo/Rib card and give them a firm shove&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shutdown took forever&lt;/strong&gt;. SQL Server can be super slow to shut down! I understand this better after reading &lt;a href="https://blogs.msdn.microsoft.com/bobsql/2016/07/04/how-it-works-xel-health-session-and-shutdown/#comment-365"&gt;a recent post on the &amp;ldquo;SQL Server According to Bob&amp;rdquo; blog&lt;/a&gt;. Bob Dorr explains that when SQL Server shuts down, it waits for all administrator (sa) level commands to complete. So, if you&amp;rsquo;ve got any servers where jobs or applications are running as sa, well&amp;hellip;.  hope they finish up fast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patching accidentally interrupted something important&lt;/strong&gt;. Some process was running from an app server, etc, that failed because patching rebooted the server, and it fired off alarms that had to be cleaned up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Something failed during startup after reboot&lt;/strong&gt;. A service started and failed, or a database wasn&amp;rsquo;t online.  (Figuring out &amp;ldquo;was that database offline before we started?&amp;rdquo; was the first step. Ugh.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Miscommunication caused a problem on a cluster&lt;/strong&gt;.  Whoops, you were working on node2 while I was working on node1? BAD TIMES.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="i-dont-believe-windows-updates-that-say-they-dont-require-a-reboot"&gt;I don&amp;rsquo;t believe Windows updates that say they don&amp;rsquo;t require a reboot.&lt;/h2&gt;
&lt;p&gt;I realize I sound like a crotchety retiree when I say, &amp;ldquo;In my day, we ALWAYS rebooted after applying patches.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;But patches that say they don&amp;rsquo;t require a reboot are dirty liars, and I don&amp;rsquo;t trust them.&lt;/p&gt;
&lt;p&gt;If stuff starts getting weird later, and you skipped the reboot during the maintenance window, you know how that&amp;rsquo;s gonna look. Not good. Always have a maintenance window, and don&amp;rsquo;t skip the restart.&lt;/p&gt;
&lt;h2 id="i-love-that-youre-already-planning-patch-verification"&gt;I love that you&amp;rsquo;re already planning patch verification!&lt;/h2&gt;
&lt;p&gt;You must have had that experience where run Windows Update and it says it worked, but then you find that it actually didn&amp;rsquo;t install one of the critical patches.&lt;/p&gt;
&lt;p&gt;Maybe we&amp;rsquo;ve all had that experience.&lt;/p&gt;
&lt;p&gt;Checking to make sure critical patch numbers all made it in during the maintenance window is super smart.&lt;/p&gt;
&lt;h2 id="separateservers-into-pets-and-cattle-sort-of"&gt;Separate servers into Pets and Cattle (sort of)&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/cattle-300x300.png"
alt="cattle" width="230"&gt;
&lt;/figure&gt;
One of the concepts of managing cloud environments is for developers to create systems where servers are no longer special little flowers with unique names. If your servers cause lots of tragedy when they get sick, then you&amp;rsquo;re vulnerable.&lt;/p&gt;
&lt;p&gt;Instead, the idea is that developers build systems where servers are more like cattle. They may be expensive, but if they get ill, you quickly &amp;ldquo;remove&amp;rdquo; them (OK, kill them) for the safety of the herd and replace them.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a brutal metaphor, but they really mean it. Everything needs to be killable.&lt;/p&gt;
&lt;p&gt;(I&amp;rsquo;m not actually sure who to credit for coming up with this comparison. Update: &lt;a href="http://www.theregister.co.uk/2013/03/18/servers_pets_or_cattle_cern/"&gt;According to The Register&lt;/a&gt;, this came from a former Microsoftie named Bill Baker.)&lt;/p&gt;
&lt;p&gt;For patching, I&amp;rsquo;ve always had groups of SQL Servers. The most critical are pets. The least critical are pretty darn close to cattle.&lt;/p&gt;
&lt;p&gt;The general groups go like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Development SQL Servers&lt;/strong&gt; &lt;strong&gt;- cattle&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Fully automated patching&lt;/li&gt;
&lt;li&gt;Something goes wrong, you spin up a new VM and redeploy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Staging SQL Servers&lt;/strong&gt; &lt;strong&gt;- cattle&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Fully automated patching&lt;/li&gt;
&lt;li&gt;Manual verification that things look normal after the patching before patches are cleared for production SQL Servers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-Critical Production SQL Servers&lt;/strong&gt;  &lt;strong&gt;- prize cattle that compete at the county fair&lt;/strong&gt;. Can be down for 2+ hours during a scheduled maintenance and it&amp;rsquo;s no problem. Wouldn&amp;rsquo;t be a huge issue if they were down all weekend after a scheduled maintenance or lost some data.
&lt;ul&gt;
&lt;li&gt;Often these get fully automated patching, depending on the tools in use and data loss requirements&lt;/li&gt;
&lt;li&gt;These are the first SQL Servers to be patched in production&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Critical Production SQL Servers&lt;/strong&gt; - &lt;strong&gt;pets&lt;/strong&gt;.
&lt;ul&gt;
&lt;li&gt;Someone is around to run the patches.&lt;/li&gt;
&lt;li&gt;In a highly automated environment, that person may mostly monitor a dashboard while the patches deploy and respond if needed. (Someone who can actually respond meaningfully, not just the Network On Call center, because usually for these servers the business would rather not wait for the NOC to page out.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It isn&amp;rsquo;t like this everywhere. I&amp;rsquo;ve had readers and clients where the development SQL Servers were NOT cattle, because they contained changes that hadn&amp;rsquo;t been checked into source control.&lt;/p&gt;
&lt;p&gt;If that&amp;rsquo;s the case where you work, you want a separate project to make changes so Development environments are entirely cattle.&lt;/p&gt;
&lt;h2 id="automated-patching-use-system-centerfor-cattle"&gt;Automated patching: use System Center for cattle&lt;/h2&gt;
&lt;p&gt;System Center is really good at deploying patches. Servers that qualify as cattle are a great fit for system center.&lt;/p&gt;
&lt;p&gt;The patches roll out. If there are issues, the Network On Call center, or whomever is on call, follows a documented process to get things back online. If there&amp;rsquo;s major issues, you restore from backup. Or possibly just redeploy from source, in the case of development servers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If &amp;ldquo;restore from backup&amp;rdquo; sets off any alarm bells for anyone, that server isn&amp;rsquo;t cattle.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="id-look-at-powershell-for-the-sql-servers-that-need-special-attention-prize-cattle-and-pets"&gt;I&amp;rsquo;d look at PowerShell for the SQL Servers that need special attention (prize cattle and pets)&lt;/h2&gt;
&lt;p&gt;For the &amp;ldquo;pet&amp;rdquo; servers, I love the idea of automation for quickly allowing you to add bells and whistles&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d consider PowerShell, because it&amp;rsquo;s a popular swiss army knife and you could work in lots of great features over time.&lt;/p&gt;
&lt;p&gt;I would try to work in features like this.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validate the last backup times for critical databases and raise a flag if they aren&amp;rsquo;t what they should be prior to starting patching.&lt;/li&gt;
&lt;li&gt;Record the status of all databases on the instance for you (ARE any offline?)&lt;/li&gt;
&lt;li&gt;Check for long running jobs&lt;/li&gt;
&lt;li&gt;Stop the SQL Server services before initiating Windows restart. This helps demystify any slow shutdown experiences, as you know exactly when the SQL Services finish stopping without having to go into Event or SQL Logs.&lt;/li&gt;
&lt;li&gt;Install and validate Windows patches&lt;/li&gt;
&lt;li&gt;Run a few verification queries as a smoketest to make sure databases are properly online and available to users&lt;/li&gt;
&lt;li&gt;Validate that all SQL Services started as expected (and didn&amp;rsquo;t fail immediately after)&lt;/li&gt;
&lt;li&gt;Check Event Logs and SQL Logs for warnings after the reboot&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Doing these things manually kinda stinks.&lt;/p&gt;
&lt;p&gt;Do I know how to do all this stuff in PowerShell? Nope. I used to do all this stuff manually, back when PowerShell was a DOS prompt&amp;rsquo;s kid brother.&lt;/p&gt;
&lt;p&gt;But if it was my job to do it now, I think PowerShell&amp;rsquo;s probably a good bet for being able to do a lot of it pretty well.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d work to get this working first in my pre-production and staging environments, then roll it out to the &amp;ldquo;prize cattle&amp;rdquo;, then to the &amp;ldquo;pet&amp;rdquo; SQL Servers last.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d leave development SQL Servers as pure cattle, though. Because I&amp;rsquo;m lazy.&lt;/p&gt;
&lt;p&gt;If your company has developers, it&amp;rsquo;s possible that you could get some of their time to work with you to get this going. You&amp;rsquo;d help explain the requirements, they&amp;rsquo;d write the code. Someone would buy donuts.&lt;/p&gt;
&lt;h2 id="cluster-aware-updating-cau"&gt;Cluster Aware Updating (CAU)&lt;/h2&gt;
&lt;p&gt;Cluster Aware Updating is a feature introduced in Windows Server 2012 to relieve some of the pain from patching Windows Failover Clusters.&lt;/p&gt;
&lt;p&gt;This helps automating:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changing nodes into maintenance mode&lt;/li&gt;
&lt;li&gt;Moving roles off the node&lt;/li&gt;
&lt;li&gt;Installing patches&lt;/li&gt;
&lt;li&gt;Restarting the node&lt;/li&gt;
&lt;li&gt;Changing the node out of maintenance mode&lt;/li&gt;
&lt;li&gt;Moving things around more&lt;/li&gt;
&lt;li&gt;Moving on to other nodes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s an option to have an administrator trigger the run from a remote server so they can monitor it real-time, or it can be set to run on a schedule on the cluster itself.&lt;/p&gt;
&lt;p&gt;There are still outages during failovers. And it doesn&amp;rsquo;t cover those bells and whistles I talked about earlier about checking for running jobs.&lt;/p&gt;
&lt;p&gt;Microsoft has published &lt;a href="https://msdn.microsoft.com/en-us/library/jj907291.aspx"&gt;a whitepaper on using Cluster Aware Updating with SQL Server 2012 and higher&lt;/a&gt; for Failover Cluster Installs of SQL Server.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Be aware this doesn&amp;rsquo;t cover Availability Groups. My understanding is that those are still unsupported for CAU, even in SQL Server 2016.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="ideally-youre-not-doing-the-patching-yourself-forever"&gt;Ideally, you&amp;rsquo;re not doing the patching yourself forever&lt;/h2&gt;
&lt;p&gt;Summing this up, as a DBA I really like automation for patching.&lt;/p&gt;
&lt;p&gt;I may want someone to be around sipping their coffee while it runs in some cases. And I&amp;rsquo;d grow the automation so that it writes clear logs, and if things DO go wrong it outputs helpful diagnostics so the person can respond more quickly.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d even try to make it so good that a junior level person could run it.&lt;/p&gt;
&lt;p&gt;DBAs never need to worry about automating themselves out of a job, oddly enough. There&amp;rsquo;s always something new that comes along that needs to be taken care of.&lt;/p&gt;
&lt;h2 id="iknow-where-you-can-find-some-powerfriends"&gt;I know where you can find some PowerFriends&lt;/h2&gt;
&lt;p&gt;I can&amp;rsquo;t help you write PowerShell. It&amp;rsquo;s not that it isn&amp;rsquo;t cool, my current specialization just lies in teaching performance tuning and &lt;a href="https://twitter.com/Kendra_Little/status/758026207883472896"&gt;drawing cat pictures&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s a SQL Server Slack community full of PowerShell loving people who do cool things with automation. And they are super helpful! You can join the Slack channel for free anytime (whether or not you wanna learn PowerShell).&lt;/p&gt;
&lt;p&gt;Go to &lt;a href="https://dbatools.io/slack/"&gt;dbatools.io/slack&lt;/a&gt; to join sqlcommunity.slack.com&lt;/p&gt;
&lt;h2 id="got-opinions"&gt;Got Opinions?&lt;/h2&gt;
&lt;p&gt;I wanna hear them! Like I said, patching hasn&amp;rsquo;t been my actual job for a long while now. If you know magical secrets, SPILL THEM.&lt;/p&gt;</description></item><item><title>Why an Upgrade can Cause Performance Regressions (Dear SQL DBA Episode 9)</title><link>https://kendralittle.com/2016/07/21/why-can-an-upgrade-cause-performance-regression-dear-sql-dba-episode-9/</link><pubDate>Thu, 21 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/21/why-can-an-upgrade-cause-performance-regression-dear-sql-dba-episode-9/</guid><description>&lt;p&gt;You finally got approval to move to new hardware and a fresher version of SQL Server. After months of work,  you do the migration and then&amp;hellip; performance gets worse. What can cause this, and what do you look for?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Prefer a podcast? Find it at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dear-sql-dba-podcast&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Show notes with clickable links are below the video. &lt;a href="https://kendralittle.com/2016/07/26/poster-troubleshooting-sql-server-after-a-migration-or-upgrade/"&gt;A poster of the concepts is here&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/QaoDS7EKABk?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s this week&amp;rsquo;s question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I recently went through a process of migrating databases on a SQL Server 2008 R2 stand alone instance to a SQL Server 2012 SP2 cluster.&lt;/p&gt;
&lt;p&gt;The cluster&amp;rsquo;s servers and SQL Server configurations were built to be as close to identical as possible to the previous instance (memory, cores, disk, maxdop, CTP, etc).&lt;/p&gt;
&lt;p&gt;After the migration, I noticed that CPU utilization jumped from the normal 25% to a consistent 75%.&lt;/p&gt;
&lt;p&gt;I did several other migrations with similar server loads with no issues, so I&amp;rsquo;m a bit puzzled as to what might be going on here. Could the upgrade from SQL Server 2008 R2 to SQL Server 2012 simply be exposing bad queries that 2008 was handling differently?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I love this topic! I&amp;rsquo;m going to go a bit broader and talk about a variety of issues I&amp;rsquo;ve seen with migrations and upgrades. Let&amp;rsquo;s get to it!&lt;/p&gt;
&lt;h2 id="review-your-max-degree-of-parallelism-and-cost-threshold-for-parallelism-settings-and-other-things-from-sysconfigurations"&gt;Review your Max Degree of Parallelism and Cost Threshold for Parallelism settings (and other things from sys.configurations)&lt;/h2&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Why-So-Tired-SQL-Server-300x300.png" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;You&amp;rsquo;ve already done this one. I&amp;rsquo;m listing it for others who might hit the same situation, because it&amp;rsquo;s an important step.&lt;/p&gt;
&lt;p&gt;SQL Server defaults &amp;ldquo;max degree of parallelism&amp;rdquo; to 0, which means when a query goes parallel, it can use all the cores. If you accidentally left that set at 0 on the new instance, your workload could have queries fighting over all CPUs all the time.&lt;/p&gt;
&lt;p&gt;For more information on how to determine these two settings, check out my last episde, &amp;ldquo;&lt;a href="https://kendralittle.com/2016/07/14/max-degree-of-parallelism-cost-threshold-for-parallelism/"&gt;Max Degree of Confusion&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;While you&amp;rsquo;re at it, compare all the settings in sys.configurations between the instances to check for differences, and look into each one. I&amp;rsquo;ve seen weird accidents cause performance issues, like people mistakenly setting minimum memory for a query on one instance.&lt;/p&gt;
&lt;h2 id="the-new-hardware-may-have-a-bottleneckthat-only-shows-up-under-load"&gt;The new hardware may have a bottleneck that only shows up under load&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve run into a couple of issues with hardware configuration that weren&amp;rsquo;t caught until after migration.&lt;/p&gt;
&lt;p&gt;In one case, the server power wasn&amp;rsquo;t completely plugged in. This led to CPUs that operated at lower power, and actually showed &lt;em&gt;higher&lt;/em&gt; percent utilization when examined in Windows task manager. They were just capable of doing less!&lt;/p&gt;
&lt;p&gt;You can detect this by doing two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the Windows System log for problematic messages &amp;ndash; in this case there were messages about power sources not being fully plugged in, but I look at all messages in the system log (some things are &amp;ldquo;informational&amp;rdquo; that are really important)&lt;/li&gt;
&lt;li&gt;Run a free tool like CPU-Z to measure the clock speed that your processors are running at&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In another case, following a migration we had one single core that was always at 100%! It turns out that our new NIC was pegging one core under load.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We saw SOS_SCHEDULER_YIELD in wait stats - when SQL Server was trying to use that one core, it had to wait a LOT, because it was being hogged by the NIC&lt;/li&gt;
&lt;li&gt;This skewed overall utilization  up&lt;/li&gt;
&lt;li&gt;We were able to fix this by tweaking settings on the NIC so that it used multiple cores - required planned maintenance&lt;/li&gt;
&lt;li&gt;This hadn&amp;rsquo;t happened on the old server, and our load testing pre migration just wasn&amp;rsquo;t chatty enough over the network to surface the issue&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="you-may-have-power-savings-enabled-on-your-processors"&gt;You may have power savings enabled on your processors&lt;/h2&gt;
&lt;p&gt;I wouldn&amp;rsquo;t expect this to make the entire difference between 25% and 75% usage, but it could be one of a few things contributing to the problem. It&amp;rsquo;s easy to fix, so it&amp;rsquo;s worth checking for.&lt;/p&gt;
&lt;p&gt;Look at the BIOS on the new servers and make sure that power savings has been disabled.&lt;/p&gt;
&lt;p&gt;Just changing the power savings settings in Windows Server does not always disable power savings, you need to look at a server management tool like Dell OpenManage or HP System Insight Manager.&lt;/p&gt;
&lt;p&gt;Use your server model and look up the manufacturer&amp;rsquo;s guide to configuration for performance. These guides will list the power settings needed to get &amp;ldquo;high performance.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Most servers these days ship with default settings that clock  the processors down, and they can be very sluggish to clock up.&lt;/p&gt;
&lt;p&gt;This typically takes a planned outage to fix: you need to make a change in the BIOS and then restart the server.&lt;/p&gt;
&lt;h2 id="your-fresh-new-sql-server-version-could-be-suffering-from-stack-dumps-or-15-second-storage-errors"&gt;Your fresh new SQL Server version could be suffering from stack dumps or &amp;ldquo;15 second&amp;rdquo; storage errors&lt;/h2&gt;
&lt;p&gt;Stack dumps typically causes periodic &amp;ldquo;freezeups&amp;rdquo; that are followed by high load. 15 second storage errors mean the storage literally isn&amp;rsquo;t responding for 15 seconds.&lt;/p&gt;
&lt;p&gt;Look in the SQL Server error log. Look pretty closely at everything for a few days for errors, then filter for the terms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Stack Dump&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;15 second&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more on 15 second errors, check out my previous episode, &amp;ldquo;&lt;a href="https://kendralittle.com/2016/06/16/outside-the-big-san-box-analyzing-storage-and-san-latency-in-sql-server-dear-sql-dba/"&gt;Outside the big SAN Box: Identifying Storage Latency in SQL Server&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="licensing-may-not-be-allowing-you-to-use-all-the-cpus--memory-banks"&gt;Licensing may not be allowing you to use all the CPUs / memory banks&lt;/h2&gt;
&lt;p&gt;If SQL Server can&amp;rsquo;t use all your CPUs, it can cause weird high CPU usage on some of them&amp;ndash; and in some cases not allow SQL Server to use all the memory on the server, which can cause unexpected slow performance patterns.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve seen this happen in a couple of different ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL Server 2012 has a weird Enterprise Install limited to 20 cores
&lt;ul&gt;
&lt;li&gt;There was an upgrade path for people using &amp;ldquo;seat based&amp;rdquo; or CAL licensing to use SQL Server 2012 Enterprise Edition, but the installation limited them to using 20 cores or less.&lt;/li&gt;
&lt;li&gt;Some people didn&amp;rsquo;t understand the upgrade licensing completely, and just didn&amp;rsquo;t realize they hadn&amp;rsquo;t licensed all the cores. In these cases CPU affinity masking can at least be used to spread the cores in use evenly across all server sockets (be very careful, affinity masking can go wrong)&lt;/li&gt;
&lt;li&gt;Once I found a case where someone had simply downloaded the incorrect install media from MSDN and it was used on all the instances at their company by accident&amp;ndash; and these servers had a lot more than 20 cores. The name of the download appeared very innocent&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sqlblog.org/2012/04/27/a-cautionary-tale-about-cal-licenses-in-sql-server-2012-enterprise"&gt;Aaron Bertrand wrote a post with lots of detail on this on SQLBlog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve also seen this happen when people are running SQL Server Standard Edition with a VM, and they configure the VM to look like it has more than 4 CPU sockets with a single core by accident&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Look in the SQL Server Error log after the last startup for the message telling you how many sockets and cores SQL Server detected and make sure it&amp;rsquo;s using all the cores it should be.&lt;/p&gt;
&lt;h2 id="something-outside-sql-server-may-be-using-cpu"&gt;Something outside SQL Server may be using CPU&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ve probably checked for this.&lt;/p&gt;
&lt;p&gt;It never hurts to doublecheck, because I&amp;rsquo;ve found surprises on servers that I manage. Stuff just creeps in. Someone decides to use the server for testing before you go live and forgets to tell you, and also forgets to turns stuff off.&lt;/p&gt;
&lt;p&gt;Or if you&amp;rsquo;re me, you did something in the middle of the night before the instance went live that you forgot about.&lt;/p&gt;
&lt;p&gt;Check the Windows task manager for processes using CPU and memory, and make sure there&amp;rsquo;s not scheduled tasks or agent jobs that are running things that didn&amp;rsquo;t used to run on the old server.&lt;/p&gt;
&lt;h2 id="you-could-be-using-a-different-version-of-the-sql-server-cardinality-estimator-on-the-new-instance"&gt;You could be using a different version of the SQL Server Cardinality Estimator on the new instance&lt;/h2&gt;
&lt;p&gt;This is specifically for folks who have upgraded to SQL Server 2014 or higher.&lt;/p&gt;
&lt;p&gt;Check your database compatibility level and related settings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database compatibility level 120 uses a new version of the &amp;ldquo;cardinality estimator&amp;rdquo;&lt;/li&gt;
&lt;li&gt;This can lead to very different plans being generated&lt;/li&gt;
&lt;li&gt;On SQL Server 2016, you can raise the database compatibility level to 120 or 130 and set LEGACY_CARDINALITY_ESTIMATION=ON for the database to use the old level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new cardinality estimator is a good thing, but some folks have found it causing performance regressions, so it&amp;rsquo;s worth checking if this is part of your issue.&lt;/p&gt;
&lt;h2 id="sql-server-may-be-optimizing-the-top-cpu-burning-queries-differently"&gt;SQL Server may be optimizing the top CPU burning queries differently&lt;/h2&gt;
&lt;p&gt;Instead of moving the files and attaching, I prefer backup and restore (or log shipping for a fast cutover).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I like to keep the old copy of the database on the old hardware for at least a month&lt;/li&gt;
&lt;li&gt;This means if a &amp;ldquo;slow query&amp;rdquo; issue comes up, I can run it against the old hardware and compare execution times, to see if it&amp;rsquo;s really slower or burns more resources&lt;/li&gt;
&lt;li&gt;I can also compare query execution plans to see if SQL Server is making a different decision about how to run the query&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You should be taking a final backup pre-migration no matter what, so you can restore that last backup and compare, even if you moved the database files to do the migration.&lt;/p&gt;
&lt;p&gt;In any case, pull the top 10 queries by total CPU usage. Look for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;large amounts of reads / indexing opportunities&lt;/li&gt;
&lt;li&gt;huge amounts of executions per minute&lt;/li&gt;
&lt;li&gt;plan warnings of any sort (these show up with a little yellow warning sign, like for roadwork)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like to pull this list prior to migration as well, so I can tell if the top queries afterward are the same or different.&lt;/p&gt;
&lt;p&gt;Free tools to pull top queries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.brentozar.com/blitzcache/"&gt;sp_BlitzCache&lt;/a&gt; from Brent Ozar Unlimited (registration required)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sqlskills.com/blogs/glenn/category/dmv-queries/"&gt;Glenn Berry&amp;rsquo;s SQL Server DMV queries from SQLSkills&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-new-bottleneck-may-have-emerged-simply-because-the-new-hardware-is-faster"&gt;A new bottleneck may have emerged simply because the new hardware is faster&lt;/h2&gt;
&lt;p&gt;Even if you&amp;rsquo;re matching things like the number of CPUs, the CPUs themselves are hopefully faster. Because hardware is just faster.&lt;/p&gt;
&lt;p&gt;And since memory is cheaper, we often have a bit more memory in the new SQL Server.&lt;/p&gt;
&lt;p&gt;When you make one thing faster, sometimes that can lead to a new bottleneck. I&amp;rsquo;ve hit this situation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migrate to a server with faster CPUs and more memory&lt;/li&gt;
&lt;li&gt;Amount of physical reads goes down, because SQL Server can cache more, and queries are faster&lt;/li&gt;
&lt;li&gt;Suddenly, blocking problems get worse because query patterns changed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For migrations, I like to capture wait statistics samples for a couple of weeks prior to the migration. That way, after the migration I can compare waits and see if anything new pops up, and track it from there.&lt;/p&gt;
&lt;p&gt;Two free tools to sample waits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.sqlskills.com/blogs/paul/capturing-wait-statistics-period-time/"&gt;Paul Randal&amp;rsquo;s wait stats script&lt;/a&gt; (SQLSkills)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.brentozar.com/askbrent/"&gt;sp_BlitzFirst from Brent Ozar Unlimited&lt;/a&gt; (registration required)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="you-could-just-be-hitting-a-weird-wait-on-the-new-version"&gt;You could just be hitting a weird wait on the new version&lt;/h2&gt;
&lt;p&gt;Good news, the wait stats check in the previous section will find this, too!&lt;/p&gt;
&lt;p&gt;Sometimes you just get unlucky, and your code hits a weird issue on a new version of SQL Server that you didn&amp;rsquo;t have on the old one. In once case I had very high CMEMTHREAD waits under load on one specific version of SQL Server.&lt;/p&gt;
&lt;p&gt;This is a pretty rare wait type and I had to do a bunch of research on it, and we eventually found a fix for our version.&lt;/p&gt;
&lt;p&gt;I always look for weird wait types, and want to compare waits pre and post migration when possible.&lt;/p&gt;
&lt;h2 id="you-could-be-getting-more-load"&gt;You could be getting more load&lt;/h2&gt;
&lt;p&gt;Sometimes people migrate right before the busy season hits. They know some load is coming, so they buy new hardware.&lt;/p&gt;
&lt;p&gt;And sometimes the person doing the DBA work doesn&amp;rsquo;t get to talk to the people who know when it&amp;rsquo;s a high or low period for load.&lt;/p&gt;
&lt;p&gt;You might be able to see this looking at top queries by execution, but another simple way to check it is by collecting a few performance counters before and after migration&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://msdn.microsoft.com/en-us/library/ms190911.aspx"&gt;&amp;ldquo;SQL Statistics&amp;rdquo; Performance Object&lt;/a&gt; has three counters that can help measure how much work your instance is doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Batch requests/sec&lt;/li&gt;
&lt;li&gt;Compilations/sec&lt;/li&gt;
&lt;li&gt;Recompilations/sec&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compilations particularly burn CPU, so whenever CPU goes up I&amp;rsquo;m always interested to see if compilation rates have risen.&lt;/p&gt;
&lt;h2 id="migration-planning-and-troubleshooting-checklists"&gt;Migration planning and troubleshooting checklists&lt;/h2&gt;
&lt;h3 id="some-planning-notes-to-make-troubleshooting-easier"&gt;Some planning notes (to make troubleshooting easier)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Keep the original server and database around as part of your plan. Do the migration with backup /restore (or possibly logshipping or mirroring to reduce downtime).
&lt;ul&gt;
&lt;li&gt;Lock accounts out of the old database and even shut of the instance if needed&lt;/li&gt;
&lt;li&gt;Keep it around for a month in case it&amp;rsquo;s needed to troubleshoot performance / compare execution plans&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Collect samples of wait stats during important periods for several weeks prior to migration, save them off&lt;/li&gt;
&lt;li&gt;Collect top sql server queries with plans by CPU, logical reads, and execution count prior to migration&lt;/li&gt;
&lt;li&gt;Collect performance counters prior to migration:
&lt;ul&gt;
&lt;li&gt;SQL Statistics - Batch requests/sec, Compilations/sec, Recompilations/sec&lt;/li&gt;
&lt;li&gt;% Processor Time&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="troubleshooting-post-migration"&gt;Troubleshooting post migration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Review your Max Degree of Parallelism and Cost Threshold for Parallelism settings&lt;/li&gt;
&lt;li&gt;Compare all the settings in sys.configurations between the instances to check for differences, and look into each one&lt;/li&gt;
&lt;li&gt;Check the Windows System log for problematic messages &amp;ndash; in this case there were messages about power sources not being fully plugged in, but I look at all messages in the system log (some things are &amp;ldquo;informational&amp;rdquo; that are really important)&lt;/li&gt;
&lt;li&gt;Run a free tool like CPU-Z to measure the clock speed that your processors are actually getting&lt;/li&gt;
&lt;li&gt;Look at the BIOS on the new servers and make sure that power savings has been disabled&lt;/li&gt;
&lt;li&gt;Look in the SQL Server Error log after the last startup for the message telling you how many sockets and cores SQL Server detected and make sure it&amp;rsquo;s using all the cores it should be&lt;/li&gt;
&lt;li&gt;Check task manager for processes using CPU and memory, and make sure there&amp;rsquo;s not scheduled tasks or agent jobs that are running things that didn&amp;rsquo;t used to run on the old server.&lt;/li&gt;
&lt;li&gt;Review SQL Server Error log for stack dumps, 15 second IO latency warnings, or other errors&lt;/li&gt;
&lt;li&gt;Check the Windows task manager for processes using CPU and memory, and make sure there&amp;rsquo;s not scheduled tasks or agent jobs that are running things that didn&amp;rsquo;t used to run on the old server&lt;/li&gt;
&lt;li&gt;Check your database compatibility level and related settings to see if you&amp;rsquo;re using the new cardinality estimator (and weren&amp;rsquo;t before) - SQL Server 2014+&lt;/li&gt;
&lt;li&gt;Identify top 10 CPU burning queries. Compare query plans against older instance. Look for large amounts of reads / indexing opportunities, or huge amounts of executions per minute.&lt;/li&gt;
&lt;li&gt;Sample SQL Server wait stats when performance is poor to see what the top waits are &amp;ndash; and if they&amp;rsquo;re surprising&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Free Poster: Cat DBA Says Not Right Meow</title><link>https://kendralittle.com/2016/07/19/free-sql-server-poster-cat-dba-says-not-right-meow/</link><pubDate>Tue, 19 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/19/free-sql-server-poster-cat-dba-says-not-right-meow/</guid><description>&lt;p&gt;You&amp;rsquo;ve got 99 problems, and the request coming in ain&amp;rsquo;t one.&lt;/p&gt;
&lt;p&gt;Maybe you need to channel your inner Cat DBA, just for a moment.&lt;/p&gt;
&lt;h2 id="about-this-poster"&gt;About This Poster&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Cat-DBA-Preview-234x300.gif"
alt="Cat DBA Preview"&gt;
&lt;/figure&gt;
&lt;p&gt;Print out this poster in full color. It will help you remember to grab your car keys and head out of the office at 4:59 PM each weekday, before another email can come in.&lt;/p&gt;
&lt;p&gt;And remember: there is no day like &lt;a href="http://icanhas.cheezburger.com/tag/Caturday"&gt;Caturday&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Coming to SQL Saturday Portland? Plan a Vacation, too!</title><link>https://kendralittle.com/2016/07/15/coming-to-sql-saturday-portland-plan-a-vacation/</link><pubDate>Fri, 15 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/15/coming-to-sql-saturday-portland-plan-a-vacation/</guid><description>&lt;p&gt;&lt;a href="http://www.sqlsaturday.com/572/eventhome.aspx"&gt;SQL Saturday Oregon&lt;/a&gt; will be held on Oct 22, 2016 this year&amp;ndash; the weekend before the SQL PASS Summit.&lt;/p&gt;
&lt;p&gt;As a Portlander, I love it when people come visit my town! Please consider taking a few extra days to enjoy checking out PDX before or after the event.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my favorite things to see, do, and eat.&lt;/p&gt;
&lt;p&gt;OK, mostly eat. This place is &lt;em&gt;delicious&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="places-to-go-things-to-do"&gt;Places to go, things to do&lt;/h2&gt;
&lt;p&gt;Walk around &lt;a href="http://www.powells.com/locations"&gt;Powell&amp;rsquo;s Books downtown&lt;/a&gt;. They have more than a million books. It&amp;rsquo;s a Portland institution.&lt;/p&gt;
&lt;p&gt;Take a bike tour around Portland. We are a city who LOVES biking and cyclists. There are many bike tour companies to choose from, &lt;a href="http://portlandbicycletours.com/tours/"&gt;here is one example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Visit &lt;a href="http://pittockmansion.org/"&gt;Pittock Mansion&lt;/a&gt; and enjoy the views of downtown. &lt;a href="http://www.forestparkconservancy.org/"&gt;Walk some nearby trails in Forest Park&lt;/a&gt;, our 5,200 acre urban forest.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.omsi.edu/"&gt;Visit OMSI - the Oregon Museum of Science and Industry&lt;/a&gt;. Heaven for kids and dorky grownups like me.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/IMG_20160619_153832-300x300.png"
alt="The view at Rowena Crest, just outside of Portland" width="230"&gt;
&lt;/figure&gt;
Selfie with the view at Rowena Crest, just outside of Portland[/caption]&lt;/p&gt;
&lt;p&gt;Rent a car and see &lt;a href="http://traveloregon.com/trip-ideas/scenic-byways/the-historic-columbia-river-highway/"&gt;amazing views and waterfalls on a day trip&lt;/a&gt;. (We have so many cool waterfalls.)&lt;/p&gt;
&lt;p&gt;Take in the &lt;a href="http://www.portlandcitygrill.com/"&gt;view at happy hour from the Portland City Grill&lt;/a&gt;. Get there when it opens to snag a window seat. The sweeping views of downtown are terrific with a soda or a martini. (I&amp;rsquo;d go somewhere else for dinner, there&amp;rsquo;s better food nearby.)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://traveloregon.com/cities-regions/greater-portland/portland/"&gt;Travel Oregon has a great list of things to see and do in Portland&lt;/a&gt;, which includes our art museums and upcoming events. (I&amp;rsquo;m still working on seeing all their 7 wonders of Oregon, very cool site.)&lt;/p&gt;
&lt;p&gt;And here&amp;rsquo;s a whole website of &lt;a href="http://www.rainydayportland.com/"&gt;things to do in Portland when it rains&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="im-obliged-to-mention-donuts-cause-theyre-famous"&gt;I&amp;rsquo;m obliged to mention donuts, &amp;lsquo;cause they&amp;rsquo;re famous&lt;/h2&gt;
&lt;p&gt;Donuts are basically a personality test in Portland. Try all three and pick your favorite.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://voodoodoughnut.com/"&gt;Voodoo Doughnuts&lt;/a&gt; - traditional taste, crazy shapes. If you love the idea of a donut named after the Old Dirty Bastard, or made in the shape of genitals, this is your donut stop.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.bluestardonuts.com/"&gt;Blue Star Donuts&lt;/a&gt; - brioche dough, so artisanal they don&amp;rsquo;t use the word &amp;ldquo;artisanal&amp;rdquo;. If you identify with the word &amp;ldquo;foodie&amp;rdquo;, this is your donut stop.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.facebook.com/PipsOriginal/"&gt;Pip&amp;rsquo;s Donuts&lt;/a&gt; - the DONUT OF THE PEOPLE. If you had a crush on Bernie Sanders and really wish you lived in Portland, this is your donut.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="dinner-reservationsrequired"&gt;Dinner reservations required&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.nodoguropdx.com/"&gt;Nodoguro&lt;/a&gt; (NE) - If sushi is your one true love, &lt;a href="http://www.nodoguropdx.com/subscribe.html"&gt;sign up for the mailing list&lt;/a&gt;, &amp;lsquo;cause tickets are released in batches and sell out super fast. This is my favorite restaurant, ever, and you can get a glimpse of why by reading &lt;a href="http://www.pdxmonthly.com/articles/2015/10/9/portland-monthly-s-restaurant-of-the-year-nodoguro"&gt;why Portland Monthly named them best restaurant of 2015&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://farmspiritpdx.com/"&gt;Farm Spirit&lt;/a&gt; (NE) - when my carnivore boyfriend wanted to take me to a vegan restaurant, I felt a little confused. Was it a trap? The food and drinks are creative and fanciful without being weird. It will turn you into a super happy vegan for at least a couple hours. (Set menu, pre-pay only.)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.beastpdx.com/about-menu/"&gt;Beast&lt;/a&gt; (NE) - If you&amp;rsquo;re a Top Chef fan, you saw chef Naomi Pomeroy win Top Chef Masters way back in Season 3. Beast does a six course, fixed price menu (substitutions &lt;em&gt;politely declined&lt;/em&gt;, as they say), and it&amp;rsquo;s stellar. Extra: Beast does a weekend brunch, and it&amp;rsquo;s one of the few places that does brunch reservations for small parties.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://langbaanpdx.com/"&gt;Longbaan&lt;/a&gt; (SE) - I haven&amp;rsquo;t actually eaten at this Thai place yet, because we got reservations six months in advance, and the six months isn&amp;rsquo;t up yet.  BUT REJOICE: &lt;a href="https://www.facebook.com/Langbaankitchen"&gt;You can watch their Facebook page to see if there&amp;rsquo;s a cancellation&lt;/a&gt;. (Seriously, what is this dinner going to be like?)&lt;/p&gt;
&lt;h2 id="no-dinner-reservations-no-problem"&gt;No dinner reservations? No problem.&lt;/h2&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Pokemon_Go_Portland_State_University-224x300.png"
alt="Strolling through Portland State University\&amp;#39;s campus in downtown PDX is a sea of Pokestops set with lures" width="230"&gt;
&lt;/figure&gt;
Strolling through Portland State University&amp;rsquo;s campus in downtown PDX is a sea of Pokestops set with lures[/caption]&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.tastynalder.com/dinner/"&gt;Tasty N Alder&lt;/a&gt; (downtown) or &lt;a href="http://www.tastynsons.com/dinner/"&gt;Tasty N Sons&lt;/a&gt; (NorthEast) - The names don&amp;rsquo;t lie. These places are &lt;em&gt;tasty&lt;/em&gt;. Great examples of Portland&amp;rsquo;s comfort food fixation. &lt;em&gt;My personal favorite for brunch.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://pokpokpdx.com/main-menu/"&gt;Pok Pok&lt;/a&gt; (SE)- Family style thai dishes. Famous chicken wings. The chef keeps his James Beard Award in the bathroom.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://departureportland.com/about-departure-portland-asian-cuisine/"&gt;Departure&lt;/a&gt; (downtown)- Gregory Gourdet of Top Chef&amp;rsquo;s place. Delicious Asian fusion, good options for eating healthy or boozing it up, if either or both of those are your thing.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.nedluddpdx.com/#an-american-craft-kitchen"&gt;Ned Ludd&lt;/a&gt; (NE) - If you&amp;rsquo;ve just had enough technology, the Luddites are there for you. They cook very simply in a wood fired oven, but the food always tastes like way more than the sum of its parts. I like this place so much, I&amp;rsquo;ve gone there on my birthday.&lt;/p&gt;
&lt;h2 id="keepin-it-casual---and-a-bit-cheaper"&gt;Keepin&amp;rsquo; it casual - and a bit cheaper&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://hatyaipdx.com/"&gt;Hat Yai&lt;/a&gt; (NE)- If the words &amp;ldquo;Fried chicken with peanuty sauce and fried roti&amp;rdquo; make you salivate, Hat Yai is your jam. This was opened by the chef from Longbaan, but you don&amp;rsquo;t have to get reservations six months in advance. It&amp;rsquo;s casual, and you&amp;rsquo;re going to get grease and peanut sauce all over your hands and face.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.pinestatebiscuits.com/menu/"&gt;Pine State Biscuits&lt;/a&gt; (four locations, one is downtown) - There is a war for &amp;ldquo;best biscuit&amp;rdquo; in Portland, and Pine State is taking it seriously. If you prefer your fried chicken on a towering biscuit sandwich, this is the place for you. Don&amp;rsquo;t be freaked out if there&amp;rsquo;s a long line, it moves very quickly.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://khaomangai.com/menu/"&gt;Nong&amp;rsquo;s Khao Man Gai&lt;/a&gt; (two food carts downtown, restaurant in NE) - if you&amp;rsquo;re that person who wants to eat at least one healthy meal in Portland, Nong&amp;rsquo;s is here for you.  Soulful Thai Chicken and Rice, plenty of healthy veggies available on the side. Nong has started bottling her sauce, I recommend buying it and putting it on &lt;em&gt;anything&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you love sandwiches (and I personally &lt;em&gt;love&lt;/em&gt; sandwiches), these two places are sammich heaven:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.bunksandwiches.com/3ylo8n9rd0d6w8c3mwzd9s9r3dhpo7"&gt;Bunk&lt;/a&gt; (3 locations, one is downtown) - I just teared up a little remembering the shrimp po&amp;rsquo;boy I had here.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lardosandwiches.com/"&gt;Lardo&lt;/a&gt; (2 locations, one is downtown) - The &amp;ldquo;dirty fries&amp;rdquo; have both pork belly and fried bits of sage in them. They will make every sandwich as a salad on request, if you need to do so to mentally justify those fries.
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Kendra-Eating-Sandwich-at-Bunk-300x300.png"
alt="Kendra-Eating-Sandwich-at-Bunk" width="230"&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dessert-becauseyou-did-all-that-walking"&gt;Dessert, because you did all that walking&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://saltandstraw.com/flavors/#portland"&gt;Salt N Straw&lt;/a&gt; (3 locations) - Trust me, way better than donuts. Best. Ice. Cream. Ever. There&amp;rsquo;s a line, but it moves fast. You can taste as many flavors as you want. They make the waffle cones fresh for you, it&amp;rsquo;s your duty to have one. They&amp;rsquo;ve usually got great non-dairy options for anyone who&amp;rsquo;s not into milk. (Dill pickle sorbet was on offer recently and it was shockingly good.)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://mauricepdx.com/"&gt;Maurice&lt;/a&gt; (downtown) - A dessert luncheonette! Get the black pepper cheesecake if they have it.&lt;/p&gt;
&lt;h2 id="if-you-like-beer-theres-a-lot-of-beer-making-around-here"&gt;If you like beer, there&amp;rsquo;s a lot of beer-making around here&lt;/h2&gt;
&lt;p&gt;But I&amp;rsquo;m completely clueless about it because I don&amp;rsquo;t drink beer.  #SorryNotSorry #MoreForYou&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.portlandbeer.org/"&gt;Portlandbeer.org looks like a good place for you to check out what we&amp;rsquo;ve got&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="i-had-to-stop-before-i-even-got-to-the-ramen-and-pizzaplaces"&gt;I had to stop before I even got to the ramen and pizza places&lt;/h2&gt;
&lt;p&gt;In the name of pizza, I must say that &lt;a href="https://lovelysfiftyfifty.wordpress.com/"&gt;everyone&amp;rsquo;s talking about Lovely&amp;rsquo;s fifty fifty&lt;/a&gt; being epic, but I haven&amp;rsquo;t been there yet.&lt;/p&gt;
&lt;p&gt;It is nothing short of a miracle that I&amp;rsquo;ve lost weight this year. I think I need to head out for a walk.&lt;/p&gt;
&lt;p&gt;BTW, we have Pokemon Go stops everywhere, of course.&lt;/p&gt;</description></item><item><title>MAXDOP of Confusion (Dear SQL DBA Episode 8)</title><link>https://kendralittle.com/2016/07/14/max-degree-of-parallelism-cost-threshold-for-parallelism/</link><pubDate>Thu, 14 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/14/max-degree-of-parallelism-cost-threshold-for-parallelism/</guid><description>&lt;p&gt;Learn how to configure the Max Degree of Parallelism and Cost Threshold for Parallelism settings in SQL Server - and how SQL Server 2014 SP2 and SQL Server 2016 change the way that SQL Server automatically configures some SQL Servers with lots of cores.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is a “listen-able” 20 minute video. Show notes with clickable links are below the video.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/l71ztZijWsQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA&amp;hellip;&lt;/p&gt;
&lt;p&gt;I am completely confused as to how to set Max Degree of Parallelism for an OLTP workload. Having looked at three recommendations recently and applied it to my own machine I get 3 different values. My machine has 1 physical CPU with 4 cores, 4 visible schedulers and a hyperthreading ratio of 4. However I&amp;rsquo;ve got recommendations to set either to 1, 2 or 4. What should it be?&lt;/p&gt;
&lt;p&gt;Sincerely,&lt;/p&gt;
&lt;p&gt;Max Degree of Confusion&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t blame you for being confused&amp;ndash; this is a tough one!&lt;/p&gt;
&lt;p&gt;The good news is that for Max Degree of Confusion&amp;rsquo;s specific question, I&amp;rsquo;ve got a clear recommendation for a default setting for &amp;ldquo;Max Degree of Parallelism&amp;rdquo; and &amp;ldquo;Cost Threshold for Parallelism&amp;rdquo;. I think you need to set both, and I&amp;rsquo;ll explain why.&lt;/p&gt;
&lt;p&gt;But for people who have a lot more cores in their servers, things are a little more interesting&amp;ndash; especially if you&amp;rsquo;re running SQL Server 2014 SP2+ or SQL Server 2016.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s break this down and talk about how to figure out the setting, then we&amp;rsquo;ll circle back to our 4 core example.&lt;/p&gt;
&lt;h2 id="settings-max-degree-of-parallelism-maxdop-and-cost-threshold-for-parallelism"&gt;Settings: Max Degree of Parallelism (&amp;ldquo;MAXDOP&amp;rdquo;) and Cost Threshold for Parallelism&lt;/h2&gt;
&lt;p&gt;When you run a query, SQL Server estimates how &amp;ldquo;expensive&amp;rdquo; it is in a fake costing unit, let&amp;rsquo;s call it Estimated QueryBucks.&lt;/p&gt;
&lt;p&gt;If a query&amp;rsquo;s Estimated QueryBucks is over the &amp;ldquo;Cost Threshold for Parallelism&amp;rdquo; setting in SQL Server, it qualifies to potentially use multiple processors to run the query.&lt;/p&gt;
&lt;p&gt;The number of processors it can use is defined by the instance level &amp;ldquo;Max Degree of Parallelism&amp;rdquo; setting.&lt;/p&gt;
&lt;p&gt;When writing TSQL, you can specify maxdop for individual statements as a query hint, to say that if that query qualifies to go parallel, it should use the number of processors specified in the hint and ignore the server level setting. (You could use this to make it use more processors, or to never go parallel.)&lt;/p&gt;
&lt;h3 id="kb2806535-helps-determine-max-degree-of-parallelism"&gt;KB 2806535 helps determine Max Degree of Parallelism&lt;/h3&gt;
&lt;p&gt;Hooray, Microsoft has published some guidance on this!&lt;/p&gt;
&lt;p&gt;KB 2806536 is titled &lt;em&gt;&lt;a href="https://support.microsoft.com/en-us/kb/2806535"&gt;Recommendations and guidelines for the &amp;ldquo;max degree of parallelism&amp;rdquo; configuration option in SQL Server&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="an-acronym-numa-nodes"&gt;An acronym: NUMA nodes&lt;/h2&gt;
&lt;p&gt;KB 2806535 explains that you need to determine two things about your hardware&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How many NUMA nodes it has&lt;/li&gt;
&lt;li&gt;How many logical processors are in each NUMA node&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="numa---simpler-than-it-sounds"&gt;NUMA - simpler than it sounds&lt;/h3&gt;
&lt;p&gt;NUMA means &amp;ldquo;Non-Uniform Memory Access.&amp;rdquo; (That doesn&amp;rsquo;t really explain much of anything, I know, but if I didn&amp;rsquo;t tell you what it stands for it would be weird.)&lt;/p&gt;
&lt;p&gt;When you buy a modern server, typically each physical CPU has many logical processors. Let&amp;rsquo;s say we buy a server with 1 physical CPU and 10 logical processors, and the server has 256GB of RAM. That 1 physical CPU is snuggled up right next to all the memory chips, and it&amp;rsquo;s really fast for all 10 logical processors to access that 256GB of RAM. Our server has one NUMA node.&lt;/p&gt;
&lt;p&gt;But what if we bought a server with 2 physical CPUs and 10 logical processors each, and 512GB of RAM? We would then have 2 NUMA nodes, because a NUMA node is just a physical CPU and its local memory. Each NUMA node would have 10 logical processors and 256GB of RAM.&lt;/p&gt;
&lt;p&gt;Logical processors &lt;em&gt;can&lt;/em&gt; access all of the memory in the server. It&amp;rsquo;s just faster for a processor to access the memory that&amp;rsquo;s hooked up to its own &amp;ldquo;NUMA node&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This is important to SQL Server, because it wants queries to be fast.&lt;/p&gt;
&lt;p&gt;If a query goes parallel, you want it to use processors from the same NUMA node and access memory local to that node (ideally).&lt;/p&gt;
&lt;h2 id="8-is-a-magic-number"&gt;8 is a magic number&lt;/h2&gt;
&lt;p&gt;The guidance in KB 2806535 is basically this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Figure out how many logical processors you have in a NUMA node&lt;/li&gt;
&lt;li&gt;If you have 8 or more logical processors in a NUMA node, generally you&amp;rsquo;ll get the best performance at maxdop 8 &lt;em&gt;or lower&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;If you have less than 8 logical processors per NUMA node, generally you&amp;rsquo;ll get the best performance setting maxdop to the number of logical processors &lt;em&gt;or lower&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why 8?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not a law or anything&amp;ndash; sometimes you can get better performance for a query with a maxdop higher than 8. And if that works out well for your workload, that&amp;rsquo;s cool!&lt;/p&gt;
&lt;p&gt;But in general, using more cores = more overhead to pull everything back together.&lt;/p&gt;
&lt;h3 id="8-may-be-lessmagical-in-sql-server-2014-sp2-and-sql-server-2016-because-of-automatic-soft-numa"&gt;8 may be less magical in SQL Server 2014 SP2 and SQL Server 2016 because of &amp;ldquo;Automatic Soft NUMA&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Hardware manufacturers are packing more and more cores in processors. SQL Server&amp;rsquo;s making some changes to scale with this.&lt;/p&gt;
&lt;p&gt;SQL Server 2014 SP2 and SQL Server 2016 have a feature called &amp;ldquo;&lt;a href="https://msdn.microsoft.com/en-us/library/ms345357.aspx"&gt;Automatic Soft NUMA&lt;/a&gt;&amp;rdquo;&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This feature is on by default in SQL Server 2016, but can be disabled using ALTER SERVER CONFIGURATION with the &lt;a href="https://msdn.microsoft.com/en-us/library/ee210585.aspx"&gt;SET SOFTNUMA argument&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;In SQL Server 2014 SP2, you can enable Automatic Soft NUMA configuration by turning on Trace Flag 8079 at the server level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When Automatic Soft NUMA is enabled, if you have more than 8 physical processors in a NUMA node, Soft NUMA will be configured when SQL Server starts up. If you&amp;rsquo;re running SQL Server in a VM, note that the hypervisor generally presents all virtual cores to the guest as physical cores&amp;ndash; whether or not you have hyperthreading enabled on the host server&amp;ndash; so this will kick in if you have more than 8 vCPUs.&lt;/p&gt;
&lt;p&gt;Messages are written to the SQL Server Error log when this occurs, so it&amp;rsquo;s very easy to check there at the time of the latest startup for information about what occurred. You can also query the &lt;a href="https://msdn.microsoft.com/en-us/library/ms175048.aspx"&gt;sys.dm_os_sys_info&lt;/a&gt; and &lt;a href="https://msdn.microsoft.com/en-us/library/bb510628.aspx"&gt;sys.dm_os_nodes&lt;/a&gt; dynamic management views for configuration information.&lt;/p&gt;
&lt;p&gt;Bob Dorr explains more about Automatic Soft NUMA configuration in his blog post, &amp;ldquo;&lt;a href="https://blogs.msdn.microsoft.com/bobsql/2016/06/03/sql-2016-it-just-runs-faster-automatic-soft-numa/"&gt;SQL 2016 - It Just Runs Faster: Automatic Soft NUMA&lt;/a&gt;&amp;rdquo; on the &amp;ldquo;SQL Server According to Bob&amp;rdquo; blog.&lt;/p&gt;
&lt;p&gt;Bob gives an example of a workload running on 2016 where a 30% gain in query performance was obtained by using Soft NUMA with &amp;ldquo;max degree of parallelism&amp;rdquo; set to the number of physical cores in a socket&amp;ndash; which was 12 in that case.&lt;/p&gt;
&lt;h2 id="fine-tuning-maxdop-and-cost-threshold-require-a-repeatable-workload"&gt;Fine tuning MAXDOP and Cost Threshold require a repeatable workload&lt;/h2&gt;
&lt;p&gt;If you &lt;em&gt;really&lt;/em&gt; care about performance, you need a repeatable benchmark for your workload. You also need to be able to run that benchmark repeatedly on the production hardware with different settings.&lt;/p&gt;
&lt;p&gt;This is one of the many reasons that performance-critical environments buy identical hardware for staging environments.&lt;/p&gt;
&lt;h2 id="so-what-to-do-with-1-numa-node-and-4-logical-processors"&gt;So what to do with 1 NUMA node and 4 logical processors?&lt;/h2&gt;
&lt;p&gt;OK, so back to Max Degree of Confusion&amp;rsquo;s question.&lt;/p&gt;
&lt;p&gt;We know that there is 1 physical CPU. That&amp;rsquo;s one NUMA node. It was 4 logical processors. So we want 4 &lt;em&gt;or lower&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Max Degree of Confusion said that this is an OLTP workload, which means we can have concurrent queries running. That&amp;rsquo;s a good argument for not using 4 &amp;ndash; one longrunning query using all 4 logical processors isn&amp;rsquo;t going to be a nice day for lots of chatty little queries.&lt;/p&gt;
&lt;p&gt;Really, the question in this situation is whether we want to go with maxdop 1 an effectively &lt;em&gt;disable&lt;/em&gt; parallelism, or go with maxdop 2 and and have some parallelism.&lt;/p&gt;
&lt;p&gt;I would personally start with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Max Degree of Parallelism set to 2&lt;/li&gt;
&lt;li&gt;Cost Threshold for Parallelism set to 50&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wait-a-second-the-kb-doesnt-talk-about-cost-threshold-for-parallelism"&gt;Wait a second, the KB doesn&amp;rsquo;t talk about Cost Threshold for Parallelism!&lt;/h2&gt;
&lt;p&gt;I know, that&amp;rsquo;s what I&amp;rsquo;d change about the KB.&lt;/p&gt;
&lt;p&gt;Remember, there&amp;rsquo;s two parts to going parallel:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is the query&amp;rsquo;s Estimated cost is over the &amp;ldquo;Cost Threshold for Parallelism&amp;rdquo;&lt;/li&gt;
&lt;li&gt;If so, how many logical processors is it allowed to use based on the &amp;ldquo;Max Degree of Parallelism&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;SQL Server&amp;rsquo;s default &amp;ldquo;Cost Threshold for Parallelism&amp;rdquo; is 5. A cost of 5 QueryBucks is a super low bar these days.&lt;/p&gt;
&lt;p&gt;This default was set back in days when processor power was a &lt;em&gt;LOT MORE SCARCE&lt;/em&gt;. Processors have gotten way faster and you can eat a lot of data pretty quickly with a single logical processor these days.&lt;/p&gt;
&lt;p&gt;When I was trained as a DBA back on SQL Server 2005, our standard was to raise Cost Threshold to 50 on every server.&lt;/p&gt;
&lt;p&gt;11 years later, that has only become less risky. I think it&amp;rsquo;s a pretty safe default now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This isn&amp;rsquo;t a law any more than the magic 8 was a law. It&amp;rsquo;s just a generalization based on observation.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="would-you-ever-set-max-degree-of-parallelism-to-1-and-disable-parallelism"&gt;Would you ever set Max Degree of Parallelism to 1 and disable parallelism?&lt;/h2&gt;
&lt;p&gt;Sure, if the application was carefully crafted to NEVER need parallelism unless a query hints it higher, maxdop 1 is the way to do that at the server level. Sharepoint is famous for this architecture.&lt;/p&gt;
&lt;p&gt;But generally parallelism is a good thing, and you want to allow parallelism for the queries that need it, and benefit for it.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Cost threshold for parallelism&amp;rdquo; is your setting for determining which queries &amp;ldquo;need&amp;rdquo; it, based on their estimated cost.&lt;/p&gt;
&lt;h2 id="links-to-learn-more"&gt;Links to learn more&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Brent Ozar talks more about these two settings and brings in SQL Server wait stats with his &lt;a href="https://www.brentozar.com/archive/2013/08/what-is-the-cxpacket-wait-type-and-how-do-you-reduce-it/"&gt;post on CXPACKET&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Paul White gave an excellent presentation on parallel query execution at the PASS Summit in 2013. It&amp;rsquo;s still just as good as when he first presented it. &lt;a href="https://www.youtube.com/watch?list=PLoGAcXKPcRvbTr23ujEN953pLP_nDyZJC&amp;amp;v=yzW5cqI0uZs"&gt;Watch the hour here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t forget to check out the &lt;a href="https://blogs.msdn.microsoft.com/bobsql/"&gt;SQL Server According to Bob&lt;/a&gt; blog, by Bob Dorr and Bob Ward of Microsoft. They&amp;rsquo;ve got that article on Automatic Soft NUMA Configuration and much more cool stuff.&lt;/li&gt;
&lt;li&gt;Arvind Shyamsundar wrote a great post on parallel insert in SQL Server 2016 with a comparison of performance at different maxdops. &lt;a href="https://blogs.msdn.microsoft.com/sqlcat/2016/07/21/real-world-parallel-insert-what-else-you-need-to-know/"&gt;Read it here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Is User Acceptance Testing Covered Under Developer Edition?</title><link>https://kendralittle.com/2016/07/12/is-user-acceptance-testing-covered-under-developer-edition/</link><pubDate>Tue, 12 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/12/is-user-acceptance-testing-covered-under-developer-edition/</guid><description>&lt;p&gt;Holy mackerel, it is!&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Abandon-Users-All-Ye-Who-Enter-1024x512.png"
alt="Abandon-Users-All-Ye-Who-Enter" width="230"&gt;
&lt;/figure&gt;
&lt;h2 id="the-exception"&gt;The Exception&lt;/h2&gt;
&lt;p&gt;I tend to think of development environments as SQL Servers where customers are surely never allowed to enter, for fear that the licensing dollars will pile up like banks of snow around the gates to the instance.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s an exception. Check out this screenshot from Microsoft&amp;rsquo;s &lt;a href="https://www.microsoft.com/en-us/server-cloud/products/sql-server-editions/sql-server-developer.aspx"&gt;SQL Server 2016 Licensing Datasheet&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Licensing-Non-Production-Use-1.png"
alt="Licensing-Non-Production-Use"&gt;
&lt;/figure&gt;
&lt;p&gt;Developer Edition allows for users of an application to do acceptance testing&amp;ndash; I&amp;rsquo;m not a licensing salesperson, a Microsoft employee, a lawyer, or Doctor House, but this wording is pretty clear on the subject to me.&lt;/p&gt;
&lt;h2 id="free-developer-edition"&gt;Free Developer Edition&lt;/h2&gt;
&lt;p&gt;And Developer Edition is now free for SQL Server 2016 and 2014 via membership in the &lt;a href="https://www.visualstudio.com/en-us/products/visual-studio-dev-essentials-vs.aspx"&gt;Visual Studio Dev Essentials program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Not only is that awesome, it&amp;rsquo;s even more awesome than I thought it was.&lt;/p&gt;
&lt;h2 id="important-limitation"&gt;Important Limitation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: the &lt;a href="http://sql2014.pl/docs/SQL_Server_2014_Licensing_Guide.pdf"&gt;SQL Server 2014 licensing guide&lt;/a&gt; is a bit longer, and notes that there&amp;rsquo;s a limitation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Customers cannot use the software in a production environment, and any test data that was used for design, development or test purposes must be removed prior to deploying the software for production use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So be very careful if your User Acceptance Testing environment is used to &amp;ldquo;stage&amp;rdquo; data that is later restored to production. Per the 2014 rules, that is a production system.&lt;/p&gt;</description></item><item><title>How to Level Up Your DBA Career (Dear SQL DBA)</title><link>https://kendralittle.com/2016/07/07/how-to-level-up-your-dba-career-dear-sql-dba/</link><pubDate>Thu, 07 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/07/how-to-level-up-your-dba-career-dear-sql-dba/</guid><description>&lt;p&gt;You&amp;rsquo;re a Junior or mid-level Database Administrator with no obvious career path. How do you grow the right skills to level up your DBA career?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Prefer a podcast instead? Find it at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dear-sql-dba-podcast&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/59nFh1zBY28?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="this-weeks-questions"&gt;This week&amp;rsquo;s questions&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Today I&amp;rsquo;m answering two questions from listeners on one hot topic: advancing your DBA career when you don&amp;rsquo;t have a mentor at work, or a clear career progression.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s so much to know within SQL and as a beginner DBA (1-2 years) that I&amp;rsquo;m not sure what’s a good starting point to becoming a great DBA. What would you say I should really take time to understand? What would take me to the next level.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a junior DBA working in a very large company with very few DBA peers, and no one I can really look up to as a Senior. Luckily Production is pretty well-tuned so my workload isn&amp;rsquo;t overwhelming, and we have consultants who take care of a lot of monitoring and backup tasks.&lt;/p&gt;
&lt;p&gt;Without a Senior DBA to mentor me and bounce ideas off of, I don&amp;rsquo;t have a good path to master my environment and move up (or on to another company). I regularly read community blogs and all the online video training I can get my hands on, but I&amp;rsquo;m still worried my skills fall short.&lt;/p&gt;
&lt;p&gt;Do you have any suggestions for &amp;ldquo;leveling up&amp;rdquo; without a Senior DBA&amp;rsquo;s guidance?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="this-is-a-choose-your-own-adventure-moment-youre-at-a-fork-in-the-road"&gt;This is a Choose Your Own Adventure moment: you&amp;rsquo;re at a fork in the road&lt;/h2&gt;
&lt;p&gt;There are two paths you can take at this point:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path 1&lt;/strong&gt;: Level up your career by &lt;strong&gt;building projects as work&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pros: This can be done entirely during working hours, and is a great resume builder&lt;/li&gt;
&lt;li&gt;Cons:
&lt;ul&gt;
&lt;li&gt;Doesn&amp;rsquo;t build your leadership or communication skills&lt;/li&gt;
&lt;li&gt;Doesn&amp;rsquo;t connect you in the community outside of your work. (And that&amp;rsquo;s the community where you&amp;rsquo;re probably going to get future jobs.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This first path can get you a decent distance, but I&amp;rsquo;m not going to talk about it much today, because for many of you I think there is a more exciting and rewarding path to consider.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Path 2&lt;/strong&gt;: Level up your career by &lt;strong&gt;building yourself as a speaker&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pros:
&lt;ul&gt;
&lt;li&gt;This builds your leadership skills, communication skills, and your technical abilities all at once&lt;/li&gt;
&lt;li&gt;It also connects you with tons of other people in your field who may want to work with you in the future, at your company, or at a different company&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cons:
&lt;ul&gt;
&lt;li&gt;This requires a significant personal time commitment&lt;/li&gt;
&lt;li&gt;Public speaking is scary for lots of people, and it takes a lot of courage to get over that&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ok-what-if-i-just-absolutely-cant-i-meant-cant-i-mean-noooo-way-will-not-everget-up-and-speak-in-front-of-people"&gt;OK, What if I just absolutely can&amp;rsquo;t, I meant can&amp;rsquo;t, I mean noooo way will not EVER get up and speak in front of people?&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a choose your own adventure moment, right?&lt;/p&gt;
&lt;p&gt;You can follow Path 1, where you build your career through doing projects at work! This can work well, particularly if you make a concerted effort to build your leadership and communication skills along with it.&lt;/p&gt;
&lt;p&gt;I have a list of specific steps you can follow to identify the right projects to propose and work on in my post, &amp;ldquo;&lt;a href="https://kendralittle.com/2016/04/26/whats-the-difference-between-a-junior-and-senior-dba/"&gt;What&amp;rsquo;s the Difference Between a Junior and Senior DBA?&lt;/a&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;OK, for the rest of you guys, who are considering it&amp;hellip;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="public-speaking-is-the-best-path-to-leveling-up-your-dba-career"&gt;Public speaking is the best path to leveling up your DBA career&lt;/h2&gt;
&lt;p&gt;I built my career slowly and steadily doing projects at work for years&lt;/p&gt;
&lt;p&gt;It can be rewarding, as long as you don&amp;rsquo;t fall into the trap of overworking yourself to burnout&lt;/p&gt;
&lt;p&gt;One problem I realized was that a lot of the knowledge I gained was domain specific&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I did cool stuff, but you could only understand how cool I was if you understood the exact technical problems I was solving&lt;/li&gt;
&lt;li&gt;Often those problems were confidential and couldn&amp;rsquo;t be explained in detail to people who didn&amp;rsquo;t work for the company&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I realized that I needed to start working a healthy number of hours. The hours my employer wanted me to work.&lt;/p&gt;
&lt;p&gt;And I needed to start doing public speaking&lt;/p&gt;
&lt;p&gt;Public speaking gave me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;New contacts in the speaker community. These are people who I could ask for feedback and bounce ideas off of. In the short term they helped me solve problems at my own job. In the long term they changed the whole trajectory of my career.&lt;/li&gt;
&lt;li&gt;A better ability to listen. This is a little counter-intuitive, because it&amp;rsquo;s &lt;em&gt;speaking&lt;/em&gt;, but as a speaker you learn to listen to questions from your audience keenly, and think about those questions for long periods.&lt;/li&gt;
&lt;li&gt;Greater confidence&lt;/li&gt;
&lt;li&gt;Improved ability to &amp;ldquo;think on my feet&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Better technical knowledge&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-most-important-note-about-beginning-to-teach-pick-the-right-topics"&gt;The most important note about beginning to teach: pick the right topics&lt;/h2&gt;
&lt;p&gt;I totally screwed this one up! I made a super common mistake: I thought I needed to blog about a &amp;ldquo;special&amp;rdquo; or &amp;ldquo;advanced&amp;rdquo; topic. Something that wasn&amp;rsquo;t &amp;ldquo;covered already&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Huge mistake. This leads to spending a lot of time getting to know a piece of nice technology that isn&amp;rsquo;t very relevant to you, or to many other people.&lt;/p&gt;
&lt;p&gt;Pick a common topic that is very useful for Junior DBAs.&lt;/p&gt;
&lt;p&gt;Something that you know at least a bit about already, and that&amp;rsquo;s relevant to your job.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re going to learn a TON about this topic. Deep details. Pick something that&amp;rsquo;s worth the investment of your time, and also worth the investment of time of lots of other Junior DBAs out there.&lt;/p&gt;
&lt;p&gt;Topics in this area are things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Backups&lt;/li&gt;
&lt;li&gt;Backups&lt;/li&gt;
&lt;li&gt;Backups&lt;/li&gt;
&lt;li&gt;(Did I say backups?)&lt;/li&gt;
&lt;li&gt;Restoring backups!&lt;/li&gt;
&lt;li&gt;SQL Server settings and configuration&lt;/li&gt;
&lt;li&gt;Database settings and configuration&lt;/li&gt;
&lt;li&gt;Any kind of maintenance&lt;/li&gt;
&lt;li&gt;Any kind of common automation&lt;/li&gt;
&lt;li&gt;And backups. Consider backups!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you catch yourself thinking, &amp;ldquo;I can&amp;rsquo;t talk about that because ExpertSpeakerX already talks about it, and I won&amp;rsquo;t be as good,&amp;rdquo; then stop.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s room for you alongside ExpertSpeakerX!&lt;/p&gt;
&lt;p&gt;In fact, the community is better with multiple speakers on core topics.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re researching and testing, include materials from a wide variety of sources, and pull from your own experience. What confused you about the topic the most at first, or what were/are you surprised by? What&amp;rsquo;s your favorite way to solve a problem with that topic, and why?&lt;/p&gt;
&lt;p&gt;You will naturally have your own voice and your own perspective.&lt;/p&gt;
&lt;h2 id="look-at-this-from-another-perspective---your-next-job-interview"&gt;Look at this from another perspective - your next job interview&lt;/h2&gt;
&lt;p&gt;Imagine you&amp;rsquo;re interviewing for a Senior DBA position, either at your company or another company&lt;/p&gt;
&lt;p&gt;The interviewer asks you some technical questions about backups&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re qualified to answer those questions, right?&lt;/p&gt;
&lt;p&gt;Picture yourself being confronted with the questions now. (It&amp;rsquo;s normal to get a little sweaty.)&lt;/p&gt;
&lt;p&gt;Now picture yourself being confronted with the questions after you&amp;rsquo;ve  presented on backups a few times, and fielded questions from the audience.&lt;/p&gt;
&lt;p&gt;So. Much. Easier.&lt;/p&gt;
&lt;p&gt;The same thing goes for pitching a new project to your boss&amp;rsquo; boss, having to fix failed backups at 3 am, and explaining what happened in an incident to a senior executive. Teaching others in the SQL Server community makes you better in all these sweaty situations.&lt;/p&gt;
&lt;h2 id="begin-by-speaking-at-a-sql-server-user-group-or-sql-saturday-event"&gt;Begin by speaking at a SQL Server User Group or SQL Saturday event&lt;/h2&gt;
&lt;p&gt;Some people say that you should always start at a local user group&lt;/p&gt;
&lt;p&gt;They tend to be small, and low pressure. A terrific choice for beginning! Find a list here: &lt;a href="http://www.sqlpass.org/PASSChapters/LocalChapters.aspx"&gt;http://www.sqlpass.org/PASSChapters/LocalChapters.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But maybe you&amp;rsquo;re not near one. Or maybe you&amp;rsquo;re like me: the closest user group when I started speaking was held at Microsoft in the building where developers coded SQL Server. Regular speakers at the group are Microsoft Program Managers, developers, and the people who literally &amp;ldquo;write the book&amp;rdquo; on SQL Server.&lt;/p&gt;
&lt;p&gt;There was NO WAY I was going to test out public speaking at my local user group&lt;/p&gt;
&lt;p&gt;So I submitted to a small SQL Saturday in Iowa. SQL Saturdays are awesome, and I got lucky&amp;ndash; one accepted me!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d never been to Iowa. I didn&amp;rsquo;t know anyone in Iowa. But I got a cheap plane ticket to Iowa.&lt;/p&gt;
&lt;p&gt;I figured if it was awful, well, all those kind strangers would just forget my name.&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t awful. I wasn&amp;rsquo;t a natural, and I was presenting on the wrong topics, but it didn&amp;rsquo;t kill me. It was a little exhilarating.&lt;/p&gt;
&lt;p&gt;And I kinda wanted to do it again.&lt;/p&gt;
&lt;p&gt;See a list of SQL Saturdays here: &lt;a href="http://sqlsaturday.com/"&gt;http://sqlsaturday.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d rather start in front of a webcam, PASS has virtual chapters, too: &lt;a href="http://www.sqlpass.org/PASSChapters/VirtualChapters.aspx"&gt;http://www.sqlpass.org/PASSChapters/VirtualChapters.aspx&lt;/a&gt;  (Seriously, really, DO USE A WEBCAM!)&lt;/p&gt;
&lt;h2 id="bring-what-you-learn-from-speaking-back-to-your-workplace"&gt;Bring what you learn from speaking back to your workplace&lt;/h2&gt;
&lt;p&gt;Although speaking isn&amp;rsquo;t part of your job, it will benefit your job&lt;/p&gt;
&lt;p&gt;Part of why I&amp;rsquo;m pushing backups so much as a topic is that speaking always teaches you a lot about your topic&lt;/p&gt;
&lt;p&gt;You learn writing the demo scripts, doublechecking things on your slides, and answering audience questions (either live or later on &amp;ndash; it&amp;rsquo;s always OK to say you don&amp;rsquo;t know and would like to check)&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll learn things that allow you to see improvements you can make at work&lt;/p&gt;
&lt;p&gt;And once you start speaking, you&amp;rsquo;ll also learn things from your peers at the events you speak at, too&lt;/p&gt;
&lt;p&gt;Regularly talk with your boss about what you learn from speaking, and from others at events&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s good for your company for you to be a public speaker, and the more they know about it, the more they&amp;rsquo;ll support you and understand why you want to go to conferences&lt;/p&gt;
&lt;h2 id="becoming-a-speaker-helps-you-and-it-helps-the-sql-server-community"&gt;Becoming a speaker helps you, and it helps the SQL Server community&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;re at a fork in the road. You&amp;rsquo;re ready to level up your career. Starting to teach others is the best thing you can do &amp;ndash; join the team of presenters and teachers! We&amp;rsquo;d love to have you.&lt;/p&gt;</description></item><item><title>Which Indexes are Disk Based in SQL Server?</title><link>https://kendralittle.com/2016/07/05/which-indexes-are-disk-based-in-sql-server/</link><pubDate>Tue, 05 Jul 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/07/05/which-indexes-are-disk-based-in-sql-server/</guid><description>&lt;p&gt;I was looking through some terms in SQL Server documentation the other day, thinking about what it&amp;rsquo;s like to learn about SQL Server&amp;rsquo;s indexes when you&amp;rsquo;re new to the field. I jotted down a note: B-tree = Rowstore = Disk Based.&lt;/p&gt;
&lt;p&gt;And then I realized that&amp;rsquo;s not quite right.&lt;/p&gt;
&lt;p&gt;Not all disk based indexes are traditional clustered and nonclustered indexes. Columnstore indexes are also disk based. Updatable Columnstore indexes use special rowstore B-trees behind the scenes. And Books Online says &amp;ldquo;rowstore&amp;rdquo; &lt;a href="https://msdn.microsoft.com/en-us/library/gg492088.aspx"&gt;also refers to Memory-Optimized tables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a drawing that maps out what is &lt;a href="https://msdn.microsoft.com/en-us/library/dn553126.aspx"&gt;disk based vs in-memory&lt;/a&gt;, followed by a list with links to some of the details.&lt;/p&gt;
&lt;h2 id="words-are-hard-show-me-adiagram"&gt;Words are Hard! Show me a Diagram&lt;/h2&gt;
&lt;p&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Indexes-Disk-Based-In-Memory-Rowstore-Columnstore-Kendra-Little.png"
alt="Indexes-Disk-Based-In-Memory-Rowstore-Columnstore-Kendra-Little"&gt;
&lt;/figure&gt;
]&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Venn diagram or practical joke? You decide!&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="disk-based"&gt;Disk Based&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Rowstore - Data stored in row format on 8KB pages
&lt;ul&gt;
&lt;li&gt;Heaps (table without a clustered index)&lt;/li&gt;
&lt;li&gt;B-trees: Clustered Indexes, Nonclustered Indexes, Filtered Indexes, Indexed Views&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Columnstore Indexes - Data stored in column format on 8KB LOB pages
&lt;ul&gt;
&lt;li&gt;Clustered Columnstore, Nonclustered Columnstore, Filtered Nonclustered Columnstore&lt;/li&gt;
&lt;li&gt;Fine print: Updatable Columnstore indexes secretly use rowstore btrees behind the scenes: &amp;ldquo;deltastore&amp;rdquo; and &amp;ldquo;delete bitmap&amp;rdquo;. (That&amp;rsquo;s not pictured in the Venn diagram above, you&amp;rsquo;ll have to imagineer it in.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notes on mixing and matching disk based rowstore and columnstore technologies&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Starting in SQL Server 2016, you can create one rowstore nonclustered index on a Clustered Columnstore table, which you might do to enforce a unique constraint or for seek query performance. &lt;a href="https://msdn.microsoft.com/en-us/library/dn913734.aspx"&gt;Read more here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Nonclustered Columnstore indexes can be created on rowstore Clustered Indexes or heaps, although the table only becomes updatable in SQL Server 2016. &lt;a href="https://msdn.microsoft.com/en-us/library/dn934994.aspx"&gt;Read more on Columnstore features by version here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="in-memory"&gt;In-Memory&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In-Memory OLTP
&lt;ul&gt;
&lt;li&gt;B-trees: Memory-optimized Nonclustered Indexes (These B-trees are different than on-disk rowstore B-trees in that they exist only in memory, contain memory addresses instead of key values, and have no fixed pages. &lt;a href="https://msdn.microsoft.com/en-us/library/mt670614.aspx"&gt;Read more here.&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Hash Indexes (A specialized index only for memory-optimized tables which &amp;ldquo;bucketizes&amp;rdquo; values. &lt;a href="https://msdn.microsoft.com/en-us/library/mt706517.aspx"&gt;Read more here&lt;/a&gt;.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For durable in-memory tables, data is written to data and delta files so it&amp;rsquo;s not lost when the database goes offline. This is very different from &amp;ldquo;disk based&amp;rdquo; tables because user transactions do NOT read from the data and delta files. &lt;a href="https://msdn.microsoft.com/en-us/library/dn553125.aspx"&gt;Read more here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="both-disk-based-and-in-memory-special-case"&gt;Both Disk Based AND In-Memory (Special Case)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Columnstore Clustered Index on a Memory-optimized table
&lt;ul&gt;
&lt;li&gt;This is persisted to disk but is ALSO required to stay in memory for access. &lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/03/07/real-time-operational-analytics-memory-optimized-table-and-columnstore-index/"&gt;See Sunil Agarwal&amp;rsquo;s post for diagrams&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Index Usage Stats Insanity - the oddities of sys.dm db index usage stats (Dear SQL DBA)</title><link>https://kendralittle.com/2016/06/30/index-usage-stats-insanity-sys-dm_db_index_usage_stats-dear-sql-dba/</link><pubDate>Thu, 30 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/30/index-usage-stats-insanity-sys-dm_db_index_usage_stats-dear-sql-dba/</guid><description>&lt;p&gt;SQL Server’s “index usage stats” dynamic management view is incredibly useful&amp;ndash; but does it tell you what you THINK it tells you?&lt;/p&gt;
&lt;p&gt;I explain the quirks of how sys.dm_db_index_usage_stats works and why the information is so valuable.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/1QlVjsvqUAk?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="question-dear-sql-dba"&gt;Question: Dear SQL DBA,&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Why does the sys.dm_db_index_usage_stats dynamic management view increment the user_updates value even when you have a where clause on a given index that would result in no change to indexed values?&lt;/p&gt;
&lt;p&gt;Sincerely,&lt;/p&gt;
&lt;p&gt;Going Insane with Index Usage Stats&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="a-quick-overview-of-the-index-usage-stats-dmv"&gt;A quick overview of the “index usage stats” DMV&lt;/h2&gt;
&lt;p&gt;sys.dm_db_index_usage_stats is a dynamic management view that reports the number of times an index is used by queries for reads or writes.&lt;/p&gt;
&lt;p&gt;The “user_updates” column is described in books online as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Number of updates by user queries. This includes Insert, Delete and Updates representing number of operations done not the actual rows affected. For example, if you delete 1000 rows in one statement, this count will increment by 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Source: &lt;a href="https://msdn.microsoft.com/en-us/library/ms188755.aspx"&gt;https://msdn.microsoft.com/en-us/library/ms188755.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are also columns for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;user_seeks&lt;/li&gt;
&lt;li&gt;user_scans&lt;/li&gt;
&lt;li&gt;user_lookups&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all named “user” to indicate that they aren’t behind the scenes system queries, which have their own columns in the view.&lt;/p&gt;
&lt;h2 id="going-insane-with-index-usage-statshas-noticed-that-the-devil-is-in-the-details"&gt;&amp;ldquo;Going Insane with Index Usage Stats&amp;rdquo; has noticed that the devil is in the details&lt;/h2&gt;
&lt;p&gt;Books online said, “For example, if you delete 1000 rows in one statement, [the count in the user_updates column] will increment by 1&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Going Insane&amp;rdquo; noticed that if your delete query deletes &lt;em&gt;zero&lt;/em&gt; rows, it will still increment the user_updates column value by 1.&lt;/p&gt;
&lt;p&gt;This is totally true, and it’s easy to reproduce like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a simple table with an identity column named “i” and make it the clustered index.&lt;/li&gt;
&lt;li&gt;Insert 10 rows with default values, so you have 10 rows, where i goes from 1 to 10&lt;/li&gt;
&lt;li&gt;Query sys.dm_db_index_usage stats for that table, and  you’ll see that user_updates reads as “10”  (the 10 insert statements you ran)&lt;/li&gt;
&lt;li&gt;Run a delete statement against the table where it deletes the row with i = 1000. That doesn’t exist, so it’ll delete 0 rows.&lt;/li&gt;
&lt;li&gt;Look at sys.dm_db_index_usage_stats again&amp;ndash; it’ll show 11 for user_updates, even though you didn’t actually delete anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="it-gets-weirder-seek-operators-that-dont-get-used-will-update-the-user_seeks-column-in-index-usage-stats"&gt;It gets weirder: seek operators that don’t get used will update the user_seeks column in index usage stats&lt;/h2&gt;
&lt;p&gt;Sometimes operators in query plans don’t actually get used at runtime.&lt;/p&gt;
&lt;p&gt;For example, the nested loop join operator looks up a value in an “inner” table/index for every row that comes back from the “outer” table/index in the join. If zero rows comes back from the “outer” table/index, the SQL Server will never go and access the “inner” table/index.&lt;/p&gt;
&lt;p&gt;But user_seeks will still be incremented by 1, even if the index wasn’t actually used at runtime by that query.&lt;/p&gt;
&lt;h2 id="even-more-weirdness-user_scans-doesnt-necessarily-indicate-that-sql-server-scanned-the-whole-index"&gt;Even more weirdness: user_scans doesn’t necessarily indicate that SQL Server scanned the whole index&lt;/h2&gt;
&lt;p&gt;When we learn about seeks vs scans, we tend to think of seeks as being super efficient and looking at just a few rows, and scans as reading all the rows in the object.&lt;/p&gt;
&lt;p&gt;It turns out this isn’t true. You can have a seek operator that reads all the rows in an index for a query. And you can have a scan operator that reads just a few rows.&lt;/p&gt;
&lt;p&gt;Let’s say your query uses a TOP. You may get a scan operator in your plan that feeds into the top. And the query may be so efficient that it quickly finds enough rows to satisfy the TOP requirement, and at that point the scan can just stop.&lt;/p&gt;
&lt;p&gt;It may only read a tiny number of pages in a huge index, but still user_scans is incremented by 1.&lt;/p&gt;
&lt;h2 id="and-finally-rollbacks-dont-decrement--undo-any-values-in-the-index-index-usage-stats-dmv"&gt;And finally, rollbacks don’t decrement / undo any values in the index index usage stats DMV&lt;/h2&gt;
&lt;p&gt;Let’s say you do run a single query that updates 1,000 rows. Like books online says, user_updates will increase by 1.&lt;/p&gt;
&lt;p&gt;If you roll back that transaction, the value stays as is. It shows the same value in user_updates as if the transaction committed successfully.&lt;/p&gt;
&lt;h2 id="heres-the-secret-usage-means-this-index-appeared-in-a-query-execution-plan"&gt;Here’s the secret: “usage” means “this index appeared in a query execution plan”&lt;/h2&gt;
&lt;p&gt;The misunderstanding here is about what’s doing the “using”. I totally get this, I had the same misunderstanding myself.&lt;/p&gt;
&lt;p&gt;Our inclination is to think the DMV answers the question, “Did I use the rows in this index?”&lt;/p&gt;
&lt;p&gt;Instead, it answers the question, “Did I run a query with an operator that could do something with this index?”&lt;/p&gt;
&lt;p&gt;It’s counting the number of times an operator shows up in a query plan, and categorizing it by type.&lt;/p&gt;
&lt;p&gt;It’s not checking if the operator is actually executed on individual runs, if it does a “full” scan, or if the transaction is rolled back.&lt;/p&gt;
&lt;h2 id="sysdm_db_index_usage_stats-is-still-incredibly-useful"&gt;sys.dm_db_index_usage_stats is still incredibly useful&lt;/h2&gt;
&lt;p&gt;Although the DMV is higher level than it appears, it still points to the indexes that get used the most&lt;/p&gt;
&lt;p&gt;It can also point you to indexes that haven’t been used at all&amp;ndash; at least since the last time usage stats were reset for that index&lt;/p&gt;
&lt;p&gt;The DMV is really useful for quick, high level insight into what indexes are most popular, and which you should put on a list to monitor, and perhaps eventually drop&lt;/p&gt;
&lt;p&gt;Sample uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reclaiming storage space/ maintenance time: which indexes aren’t used?&lt;/li&gt;
&lt;li&gt;Adding a column or modifying an index: how popular is it? (Quick assessment of risk)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-does-index-usage-stats-get-reset"&gt;When does index usage stats get reset?&lt;/h2&gt;
&lt;p&gt;Index usage stats is always reset when a database goes offline (that includes restarting the SQL Server or failing the database over)&lt;/p&gt;
&lt;p&gt;Dropping an index or CREATE with DROP_EXISTING will also reset usage stats&lt;/p&gt;
&lt;p&gt;In SQL Server 2012, a bug occurred where index rebuilds started resetting index usage stats&lt;/p&gt;
&lt;p&gt;The issue is specific to ALTER INDEX REBUILD (not a reorganize command)&lt;/p&gt;
&lt;p&gt;That has been fixed in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL Server 2012 SP3 + CU3&lt;/li&gt;
&lt;li&gt;SQL Server 2014 SP2 (planned as of this recording)&lt;/li&gt;
&lt;li&gt;SQL Server 2016&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More detail: &lt;a href="https://kendralittle.com/2016/03/07/sql-server-2016-rc0-fixes-index-usage-stats-bug-missing-indexes-still-broken/"&gt;/2016/03/07/sql-server-2016-rc0-fixes-index-usage-stats-bug-missing-indexes-still-broken/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="getting-back-to-the-question-about-user_updates---how-can-we-solve-that"&gt;Getting back to the question about user_updates - how can we solve that?&lt;/h2&gt;
&lt;p&gt;If you want specific data about how many writes occur in an index, you have a few options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tracing with SQLTrace or Extended events: more impact on the instance, but more complete info&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Looking at sys.dm_exec_query_stats for queries that reference the index: lightweight, but may miss information for queries whose plans aren’t in cache&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Grant Fritchey has a great post on doing this easily by joining to sys.dm_exec_text_query_plan - search for “Grant Querying Plan Cache Simplified” (&lt;a href="http://www.scarydba.com/2012/07/02/querying-data-from-the-plan-cache/"&gt;http://www.scarydba.com/2012/07/02/querying-data-from-the-plan-cache/&lt;/a&gt; )&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Tracking activity with QueryStore and looking for queries that modify the index: SQL Server 2016 only.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-about-operational-stats"&gt;What about Operational Stats?&lt;/h2&gt;
&lt;p&gt;There is a DMV, sys.dm_db_index_operational_stats that includes more granular information about writes&lt;/p&gt;
&lt;p&gt;It’s sensitive to memory pressure, though. Data goes away when metadata for that index is no longer in memory&lt;/p&gt;
&lt;p&gt;“How many writes since when?” is super hard to answer with this DMV&lt;/p&gt;
&lt;p&gt;If you’re putting in a lot of time on answering the question, you’re better off with sys.dm_exec_query_stats and friends, in my experience&lt;/p&gt;
&lt;h2 id="index-tuning-can-be-complex-but-it-has-a-great-payoff"&gt;Index tuning can be complex, but it has a great payoff&lt;/h2&gt;
&lt;p&gt;This is worth your time investment! Indexes are critical to performance.&lt;/p&gt;
&lt;p&gt;Stick with it and don’t sweat the small stuff.&lt;/p&gt;</description></item><item><title>SPLIT in a LEFT Partition Function: Where Does the Above-Boundary Data Go?</title><link>https://kendralittle.com/2016/06/28/split-in-a-left-partition-function-where-does-the-above-boundary-data-go/</link><pubDate>Tue, 28 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/28/split-in-a-left-partition-function-where-does-the-above-boundary-data-go/</guid><description>&lt;p&gt;Table partitioning seems simple, but there&amp;rsquo;s a lot of complexity in designing and managing it if you decide to use filegroups and splitting.&lt;/p&gt;
&lt;p&gt;When you first implement partitioning in this scenario, you decide where you&amp;rsquo;re going to keep &amp;ldquo;out of bound&amp;rdquo; data when you create your partition scheme. Be careful when you make that decision, because it may not be easy to change later.&lt;/p&gt;
&lt;p&gt;&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/Whered-I-put-that-data-squirrel-1024x512.png"
alt="Whered I put that data squirrel" width="230"&gt;
&lt;/figure&gt;
Let me show you what I mean.&lt;/p&gt;
&lt;h2 id="meet-our-left-based-partition-function"&gt;Meet our LEFT based partition function&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say we want to partition a table that uses the datetime data type. We want to partition on a daily basis and assign each partition to its own filegroup.&lt;/p&gt;
&lt;p&gt;We decided we want to use a &amp;ldquo;LEFT&amp;rdquo; based partition, meaning that the boundary points dividing our partitions are an &amp;ldquo;upper&amp;rdquo; bound and the boundary point sticks with the partition to the left of it.&lt;/p&gt;
&lt;p&gt;We don&amp;rsquo;t want the data for midnight to be in a different partition, so we do this by making the boundary point the very last moment in the day for the DATETIME data type, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf_splitthis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2015-12-31 23:59:59.997&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-01 23:59:59.997&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-02 23:59:59.997&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-03 23:59:59.997&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yep, the precision of ye olde DATETIME datatype is such that .997 is the last moment in the day.&lt;/p&gt;
&lt;h2 id="the-partition-schememaps-the-data"&gt;The partition scheme maps the data&lt;/h2&gt;
&lt;p&gt;After I create my partition function, I need to map where the data goes. I do that with this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps_splitthis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf_splitthis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;fg_splitthis_A&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_splitthis_B&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_splitthis_C&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_splitthis_D&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_outofbounds&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With my left-based partition function, here&amp;rsquo;s what the data assignment looks like:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Boundary-Point-Map-1.png"
alt="Boundary Point Map"&gt;
&lt;/figure&gt;
&lt;h2 id="note-that-there-is-no-boundary-point-mapped-to-fg_outofbounds"&gt;Note that there is no boundary point mapped to fg_outofbounds&lt;/h2&gt;
&lt;p&gt;Our highest boundary point is 2016-01-02 23:59:59.997, which is mapped to the filegroup to its LEFT&amp;ndash; fg_splitthis_D.&lt;/p&gt;
&lt;p&gt;I create a table on the partition scheme and insert some rows for January 1, January 2, and January 3.  Here&amp;rsquo;s what the metadata looks like after that.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/filegroup_mapping_before_split-1.png"
alt="filegroup_mapping_before_split"&gt;
&lt;/figure&gt;
&lt;h2 id="now-i-split"&gt;Now I SPLIT&lt;/h2&gt;
&lt;p&gt;I want to add a new partition, assigned to a new filegroup. I add the filegroup and file to my database.&lt;/p&gt;
&lt;p&gt;To split, I need to tell SQL Server where to put the data for the next boundary point I define. I do this with ALTER PARTITION SCHEME and setting the NEXT USED property. Then I can add my boundary point:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps_splitthis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;NEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_splitthis_E&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf_splitthis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SPLIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-04 23:59:59.997&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After making this change, here&amp;rsquo;s what my filegroup mapping looks like now:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/filegroup_mapping_after_split-1.png"
alt="filegroup_mapping_after_split"&gt;
&lt;/figure&gt;
&lt;p&gt;Our new boundary point specifies that data for January 4 goes on fg_splitthis_E.&lt;/p&gt;
&lt;h2 id="data-above-the-last-boundary-point-which-is-now-the-4th-still-goes-to-fg_outofbounds"&gt;Data above the last boundary point (which is now the 4th) still goes to fg_outofbounds&lt;/h2&gt;
&lt;p&gt;I can continue to set NEXT_USED and split, but that won&amp;rsquo;t change the filegroup assignment for data above the last boundary point in my LEFT based partition function. fg_outofbounds is where any data above &lt;em&gt;whatever&lt;/em&gt; is the highest value boundary point will go. Its partition_id is not changing when I SPLIT.&lt;/p&gt;
&lt;h2 id="why-do-people-care"&gt;Why do people care?&lt;/h2&gt;
&lt;p&gt;This might be very confusing if I&amp;rsquo;d happened to have named that filegroup fg_splitthis_20160104, or something that looked like it was assigned to a specific date.&lt;/p&gt;
&lt;h2 id="can-i-change-fg_outofbounds-to-a-different-filegroup"&gt;Can I change fg_outofbounds to a different filegroup?&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where it gets awkward. The only ALTER option for PARTITION SCHEME is to set NEXT USED. And next used only sets which filegroup will accept a new partition created by a boundary point. That doesn&amp;rsquo;t help us.&lt;/p&gt;
&lt;p&gt;The only way I know of to change where data above the highest boundary point in a LEFT based partition scheme goes is to do something like this in an outage window:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure the partition using fg_outofbounds is empty. (If not, add the appropriate filegroup, etc)&lt;/li&gt;
&lt;li&gt;Create a new partition scheme on your partition function with all the filegroups the same, except for fg_outofbounds (which is wherever you want it to be)&lt;/li&gt;
&lt;li&gt;Create a new table that matches your old table (except for names) on the new partition scheme with matching indexes and constraints&lt;/li&gt;
&lt;li&gt;Switch all the non-empty partitions to the new table&lt;/li&gt;
&lt;li&gt;Make sure identities are properly seeded&lt;/li&gt;
&lt;li&gt;Rename everything&lt;/li&gt;
&lt;li&gt;Cross every finger and toe that I didn&amp;rsquo;t forget something on this list&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That doesn&amp;rsquo;t sound like much fun. (If you know of a less painful way, let me know in the comments!)&lt;/p&gt;
&lt;p&gt;And honestly, usually it&amp;rsquo;s not worth fixing. We probably shouldn&amp;rsquo;t be allowing data in outside the boundary points anyway.&lt;/p&gt;
&lt;p&gt;But yeah, managing this isn&amp;rsquo;t so easy.&lt;/p&gt;
&lt;h2 id="takeaways-be-careful-when-designing-partitioning"&gt;Takeaways: Be Careful When Designing Partitioning&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s not actually so easy to change everything later. Be careful deciding how you want to use filegroups, and how many you want to manage. &lt;a href="https://kendralittle.com/2016/02/02/sliding-window-table-partitioning-what-to-decide-before-you-automate/"&gt;More info on making that decision is in my post here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Learn Index Tuning at the PASS Summit in 2016!</title><link>https://kendralittle.com/2016/06/24/learn-index-tuning-at-the-pass-summit-in-2016/</link><pubDate>Fri, 24 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/24/learn-index-tuning-at-the-pass-summit-in-2016/</guid><description>&lt;p&gt;I&amp;rsquo;m excited to announce that I&amp;rsquo;ll be giving a pre-conference session on index tuning, plus a general session on locking and blocking at the PASS Summit in Seattle this October! Here&amp;rsquo;s a description and a video to tell you all about these sessions.&lt;/p&gt;
&lt;h2 id="sql-server-index-formulas-problems-and-solutions"&gt;SQL Server Index Formulas: Problems and Solutions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Tuesday, Oct 25, 2016&lt;/strong&gt; &lt;strong&gt;All day training session - $495&lt;/strong&gt; &lt;strong&gt;PASS Summit Preconference training day - &lt;a href="http://www.sqlpass.org/summit/2016/RegisterNow.aspx"&gt;Register here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/_cTSlDZbU?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Every SQL Server developer must know the essentials of clustered and non-clustered index design to build fast and reliable applications. You need scripts to show when a new non-clustered index, filtered index, or indexed view will improve performance on a live SQL Server workload, and the skills to design the best index.&lt;/p&gt;
&lt;p&gt;In this example-packed full-day session, you will work through a series of problems and solutions to learn how to create and tune indexes. You will learn how to select and order key columns, when included columns help, when to use special indexes, and when to drop indexes. You will see how SQL Server 2016’s new Query Store feature offers you new tools for improving your indexes, and how Query Store compares to index dynamic management views.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll leave with all the scripts for the problems and solutions covered in the course, plus a set of additional exercises to keep building your index skills.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.sqlpass.org/summit/2016/RegisterNow.aspx"&gt;Register for this day of learning on the SQLPASS website&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-great-performance-robbery-locking-problems-and-solutions"&gt;The Great Performance Robbery: Locking Problems and Solutions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Exact date TBD  (Oct 26-28, 2016)&lt;/strong&gt; &lt;strong&gt;75 minutes&lt;/strong&gt; &lt;strong&gt;PASS Summit general session - &lt;a href="http://www.sqlpass.org/summit/2016/RegisterNow.aspx"&gt;Register for the SQLPASS conference here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/6OAkdjvawGQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Your SQL Server is slow, and you suspect blocking. You need to identify the culprit and plan the right solution at the lowest cost. In this session you will work through three common scenarios where blocking problems steal your performance and leave you frustrated. You will learn how to cut through the confusion with the right scripts to prove your case and justify your solution.&lt;/p&gt;
&lt;p&gt;I hope to see you in Seattle this fall!&lt;/p&gt;</description></item><item><title>Fail Over, Fail Again, Fail Better - Preparing for Disaster Recovery (Dear SQL DBA)</title><link>https://kendralittle.com/2016/06/23/fail-over-fail-again-fail-better-preparing-for-disaster-recovery-dear-sql-dba/</link><pubDate>Thu, 23 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/23/fail-over-fail-again-fail-better-preparing-for-disaster-recovery-dear-sql-dba/</guid><description>&lt;p&gt;You’re setting up SQL Server log shipping for disaster recovery. What else do you need to do to best prepare for a failure?&lt;/p&gt;
&lt;p&gt;Prefer a podcast instead? Find it at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dear-sql-dba-podcast&lt;/a&gt;.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/qUDdNFgeENs?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="this-weeks-question-dear-sql-dba"&gt;This Week’s Question: Dear SQL DBA&amp;hellip;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;We are going to start log shipping to reduce our time to recover from an outage. What can I do proactively to make things easier on myself when I want to switch over to the disaster recovery site (especially if the original system is unavailable)? I&amp;rsquo;m particularly worried about syncing user accounts, and dealing with SQL Agent jobs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One of my favorite quotes is from Samuel Beckett. “Ever tried. Ever failed. No matter. Try again. Fail again. Fail better.”&lt;/p&gt;
&lt;p&gt;When things go terribly wrong, our job as DBAs is to make it the &lt;em&gt;best failure possible&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="simply-setting-up-logshipping-mirroring-clustering-or-an-availability-group-isnt-enough"&gt;Simply setting up logshipping, mirroring, clustering, or an availability group isn’t enough&lt;/h2&gt;
&lt;p&gt;The fact that you’re thinking about this is great!&lt;/p&gt;
&lt;p&gt;You’re right, there are two major types of fail-overs that you have to think about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Planned failover, when you can get to the original production system (at least for a short time)&lt;/li&gt;
&lt;li&gt;Unplanned failover, when you cannot get to it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even when you’re doing a planned failover, you don’t have time to go in and script out settings and jobs and logins and all that stuff.&lt;/p&gt;
&lt;p&gt;Timing is of the essence, so you need minimal manual actions.&lt;/p&gt;
&lt;p&gt;And you really should have documentation so that whomever is on call can perform the failover, even if they aren’t you.&lt;/p&gt;
&lt;h2 id="step-1-you-need-a-safe-test-environment-with-the-same-security-and-network-setup-as-production"&gt;Step 1: You need a safe test environment with the same security and network setup as production&lt;/h2&gt;
&lt;p&gt;One of the biggest risks in solving this problem is “whoops, I was was trying to plan for disaster, and accidentally messed up production.”&lt;/p&gt;
&lt;p&gt;You need an environment where you can restore all the databases, set up tools, and test things out. I usually call this &amp;ldquo;prod test&amp;rdquo;, but it goes by &amp;ldquo;staging&amp;rdquo; sometimes as well.&lt;/p&gt;
&lt;p&gt;You want it to be as similar as possible&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If your production environment has one domain and the DR environment has another, you want the same setup with the same trust relationship. It is safer for you for prod test to not be in the actual production and DR domains, though.&lt;/li&gt;
&lt;li&gt;Same thing for firewall rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don’t cut corners with security to make things easier for disaster failover.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cutting corners with security could cause its OWN disaster&lt;/li&gt;
&lt;li&gt;You do not want an attacker who compromises your DR site to have access to accounts that give them the production environment as well&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use color coding on registering the instance names in SSMS so you know what domain you’re connected to.&lt;/p&gt;
&lt;p&gt;I like using ye olde &lt;a href="https://technet.microsoft.com/en-us/sysinternals/bginfo.aspx?f=255&amp;amp;MSPPError=-2147217396"&gt;BGINFO.exe&lt;/a&gt; (free tool from Microsoft&amp;rsquo;s Sysinternals team) to color code desktops for when you remote desktop, too.&lt;/p&gt;
&lt;h2 id="step-2-decide-on-your-balance-between-process-and-automation"&gt;Step 2: Decide on your balance between process and automation&lt;/h2&gt;
&lt;p&gt;If you just have a few SQL Server instances to manage for disaster recovery, you may prefer a manual process where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You get the logins and jobs in sync at first&lt;/li&gt;
&lt;li&gt;You change your release process so that every time security or a job changes, you deploy the change to both production and DR&lt;/li&gt;
&lt;li&gt;You audit the two environments once every six weeks to make sure they’re in sync&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This can be easier for things like creating a new domain security group in the environments, particularly if you don’t have the permissions to automate something like that yourself.&lt;/p&gt;
&lt;p&gt;It can also be simpler for things like adding a linked server, where the linked server name is going to be different in the environments.&lt;/p&gt;
&lt;p&gt;But if you’re managing more than a couple of instances, and if you have a lot of people who can deploy changes to the SQL Servers, doing it 100% manually just isn’t going to work. In that case you may want to have more automation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nightly scripts that look for new SQL Server Agent jobs and copy them to the DR environment (you probably want to leave them disabled until they are reviewed in case there’s any chance they can alter production in a negative way)&lt;/li&gt;
&lt;li&gt;Nightly scripts that look for changes in logins and stage or execute changes appropriately&lt;/li&gt;
&lt;li&gt;Nightly scripts that look for linked server changes and stage changes in DR or notify you&lt;/li&gt;
&lt;li&gt;Audit the two environments every six weeks, because no automation is perfect. And weird things like Windows Scheduled Tasks can sneak in (even though they shouldn’t)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“Staging changes” in this case means generating and saving a script for you when you aren’t sure that it’s safe to just set something loose.&lt;/p&gt;
&lt;h2 id="step-3-test-out-powershell-tools-for-your-automation-needs"&gt;Step 3: Test out powershell tools for your automation needs&lt;/h2&gt;
&lt;p&gt;Good news: you don&amp;rsquo;t have to write everything from scratch. Check out free tools that others have created.&lt;/p&gt;
&lt;p&gt;One example is dbatools.io: &lt;a href="https://dbatools.io/getting-started/"&gt;https://dbatools.io/getting-started/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Disclaimer: I didn’t write this, and I only know enough PowerShell to be dangerous. &lt;em&gt;VERY dangerous&lt;/em&gt;. But you’ve got a test environment, right?&lt;/p&gt;
&lt;p&gt;Consider testing this (or other tools) out and adapting them to your needs instead of writing all your code from scratch.&lt;/p&gt;
&lt;p&gt;For SQL Server login setup, Microsoft has a KB with a script to transfer logins. I believe this is handled by dbatools.io if you use it (but test for your setup, because I don&amp;rsquo;t know my PowerShell from my Power Rangers)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Script for transferring logins using TSQL - KB 918992: &lt;a href="https://support.microsoft.com/en-us/kb/918992"&gt;https://support.microsoft.com/en-us/kb/918992&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-4-practice-planned-and-unplanned-failovers-in-your-test-environment"&gt;Step 4: Practice planned AND unplanned failovers in your test environment&lt;/h2&gt;
&lt;p&gt;You are totally right to worry more about unplanned failovers&lt;/p&gt;
&lt;p&gt;But test planned failovers first, because it’s still hard!&lt;/p&gt;
&lt;h3 id="4-a-planned-failovers"&gt;4. A Planned failovers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;With logshipping, it’s important to know how to take the last log backup and make sure that no changes can get into the database&lt;/li&gt;
&lt;li&gt;You do a special last log backup with NO RECOVERY.  You restore that to the secondary, and  you can reverse the logshipping without re-setting up the whole thing.&lt;/li&gt;
&lt;li&gt;That could actually come in handy for some situations, so it’s worth getting really comfortable with in your test environment.&lt;/li&gt;
&lt;li&gt;You also need steps to turn on backups in the DR site after you fail over. Will you do that manually, or automate it?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After failover, test that the application tier can access the database. Even a basic minimal test will help, because it’ll help you find things that need to be reset or modified after databases fail over. Things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Orphaned Users”. If you use SQL Authentication, you may need to use sp_change_users_login to fix this, and it’s always good to check for it.&lt;/li&gt;
&lt;li&gt;Trustworthy database property: this restores as “off”. Not all databases require this, so don’t just set it on everywhere&amp;ndash; you should only enable it for databases that need it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Build a checklist for your planned failover. This will also work as a draft for your checklist for unplanned failovers.&lt;/p&gt;
&lt;h3 id="4b-unplanned-failovers"&gt;4.B Unplanned failovers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;When practicing unplanned failovers, turn off the logshipping publisher in your test environment entirely, so you can’t get to it, then run your practice.&lt;/li&gt;
&lt;li&gt;One of the big questions you’ll be asked in a real scenario is “how much data did we lose, and can we get it back once production is back online?”&lt;/li&gt;
&lt;li&gt;Practice estimating how many log backups may have been taken, but not copied to the secondary&lt;/li&gt;
&lt;li&gt;Practice the scenario of bringing the secondary online, then getting access to the original production environment back after an hour
&lt;ul&gt;
&lt;li&gt;If you don’t drop the original production databases, do you have space to make it a secondary again?&lt;/li&gt;
&lt;li&gt;If you DO drop the original production databases, how much data will be lost that never made it to the secondary, and what is the business impact?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Evaluating your risks in the DR environment&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How long will it be acceptable to run in the DR environment without logshipping set up to another failover environment?&lt;/li&gt;
&lt;li&gt;How much space do you have in the DR environment for full / differential / log backups?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usually practicing DR failures end up with you realizing you need more space and resources than you originally planned&lt;/p&gt;
&lt;p&gt;That’s totally normal - just make sure you ask for it &lt;em&gt;before&lt;/em&gt; the disaster.&lt;/p&gt;
&lt;h2 id="step-5-practice-planned-failovers-in-your-production-environment"&gt;Step 5: Practice planned failovers in your production environment&lt;/h2&gt;
&lt;p&gt;Companies that are serious about planning for failure practice failovers in production. They do it often.&lt;/p&gt;
&lt;p&gt;The more often you fail over, the better you get at it. And if you don’t keep up at it, things sneak in that break your processes and automation.&lt;/p&gt;
&lt;p&gt;You can’t do this by yourself. Failing over is about a lot more than the databases.&lt;/p&gt;
&lt;p&gt;But once you’re practicing regularly outside of production and also getting your processes and production environment ready, too, it’s time to start suggesting planned production failovers&lt;/p&gt;
&lt;p&gt;Even if the answer is “no”, keep bringing it up on a regular basis in a friendly, positive way.&lt;/p&gt;
&lt;p&gt;Got an annual review? An annual review is a great time to bring this up as a place you think your team can improve, and a way you’d like to contribute with the entire IT team.&lt;/p&gt;
&lt;h2 id="recap---failing-better"&gt;Recap - Failing better&lt;/h2&gt;
&lt;p&gt;Here’s the five steps toward disaster preparedness&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Step 1: Set up a safe test environment with the same security and network setup as production&lt;/li&gt;
&lt;li&gt;Step 2: Decide on your balance between process and automation&lt;/li&gt;
&lt;li&gt;Step 3: Test out powershell tools for your automation needs&lt;/li&gt;
&lt;li&gt;Step 4: Practice planned AND unplanned failovers in your test environment&lt;/li&gt;
&lt;li&gt;Step 5: Practice planned failovers in your production environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if you can’t complete step 5 (because you can’t do that alone), don’t forget to brag on  yourself.&lt;/p&gt;
&lt;p&gt;Write up a summary of the work you’ve done for your manager. If you’re blocked due to time or outside resources, summarize what you’d like to do further and what can help you make that happen.&lt;/p&gt;
&lt;p&gt;This is the kind of project that people outside your team might not think to ask about. But it’s fantastic work for your team to do, and it’s something you should make sure to talk about!&lt;/p&gt;</description></item><item><title>Will Query Store Work in a Read Only Database?</title><link>https://kendralittle.com/2016/06/21/will-query-store-work-in-a-read-only-database/</link><pubDate>Tue, 21 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/21/will-query-store-work-in-a-read-only-database/</guid><description>&lt;p&gt;For static databases, it&amp;rsquo;s quite useful to set SQL Server&amp;rsquo;s &amp;ldquo;read only&amp;rdquo; database property to true. When the database is read-only, it ensures that the last backup you took is still valid&amp;hellip; as long as nothing bad happens to that backup file.&lt;/p&gt;
&lt;p&gt;But can SQL Server 2016&amp;rsquo;s Query Store feature work with a read only database?&lt;/p&gt;
&lt;p&gt;I tested this out on the &lt;a href="https://github.com/Microsoft/sql-server-samples/tree/master/samples/databases/wide-world-importers"&gt;new WideWorldImporters sample database from Microsoft&lt;/a&gt;. I made sure Query Store was working in the database, then set the database to read-only.&lt;/p&gt;
&lt;p&gt;Upon refreshing my Query Store report&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/Query-Store-Read-Only.jpg"
alt="Query Store Read Only"&gt;
&lt;/figure&gt;
&lt;h2 id="life-lesson-your-desired-state-may-not-be-your-actual-state"&gt;Life Lesson: Your Desired State May Not Be Your Actual State&lt;/h2&gt;
&lt;p&gt;If we take a look into sys.database_query_store_options, we get some insight into what&amp;rsquo;s going on here:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/database_query_store_options-1.png"
alt="database_query_store_options"&gt;
&lt;/figure&gt;
&lt;p&gt;Our desired state is READ_WRITE, but our actual state is READ_ONLY. Reason: 1.&lt;/p&gt;
&lt;p&gt;Digging into the documentation, &lt;a href="https://msdn.microsoft.com/en-us/library/dn818146.aspx"&gt;the possible reasons our query store might go READ_ONLY include&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 - The database is read only&lt;/li&gt;
&lt;li&gt;2 - The database is single-user (I guess if you&amp;rsquo;re the only user, you&amp;rsquo;re responsible for monitoring your own query performance)&lt;/li&gt;
&lt;li&gt;4 - The database is in emergency mode (seems totally fair)&lt;/li&gt;
&lt;li&gt;8 - &amp;ldquo;log accept&amp;rdquo; mode. I&amp;rsquo;m not sure what this is. This is what you&amp;rsquo;ll see on readable secondaries (&lt;a href="https://twitter.com/rusanu/status/745280858186100736"&gt;thanks to @rusanu for this info&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;65536 - Query Store outgrew the allotted size you configured for it&lt;/li&gt;
&lt;li&gt;131072 - Query Store reached the memory limit allowed for it in your version of SQL Database (this only applies if you&amp;rsquo;re using SQL Database)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="if-you-need-query-store-your-database-must-be-read-write"&gt;If You Need Query Store, Your Database Must Be Read-Write&lt;/h2&gt;
&lt;p&gt;At least for now, Query Store can only record query performance in databases that are read-write. Once you go read-only you can review the performance of past queries, but you can&amp;rsquo;t track the performance of anyone who queried the database after the point it went read-only.&lt;/p&gt;
&lt;p&gt;At least for now. Query Store is such an awesome feature that perhaps this will change in the future. (I don&amp;rsquo;t have any inside info, only optimism.)&lt;/p&gt;
&lt;h2 id="want-a-workaround"&gt;Want a Workaround?&lt;/h2&gt;
&lt;p&gt;While the database must be read-write, Query Store uses only the Primary filegroup. You can potentially move your tables to a read-only filegroup and make it the default, but you&amp;rsquo;ll have to write custom code to keep anyone from using the Primary filegroup, or any other read-write filegroup. &lt;a href="http://www.sqldoubleg.com/2016/07/12/sql-server-2016-using-the-query-store-for-read-only-databases/"&gt;Read more on the SQLDoubleG blog&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Outside the Big SAN Box: Identifying Storage and SAN Latency in SQL Server (Dear SQL DBA)</title><link>https://kendralittle.com/2016/06/16/outside-the-big-san-box-analyzing-storage-and-san-latency-in-sql-server-dear-sql-dba/</link><pubDate>Thu, 16 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/16/outside-the-big-san-box-analyzing-storage-and-san-latency-in-sql-server-dear-sql-dba/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,
What do you say to a SAN admin when you think that the billion dollar SAN *may* be the bottleneck and you just want to look into it. What are the technical things I need to say to make them believe there might be something to my questions?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: This is a "listen-able" 36 minute video. You can also listen to this as a podcast - learn how at &lt;a href="https://kendralittle.com/dear-sql-dba-podcast/"&gt;kendralittle.com/dearsqldba&lt;/a&gt;.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/pWhBSvTkUfI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="this-question-is-near-and-dear-to-my-heart"&gt;This question is near and dear to my heart&lt;/h2&gt;
&lt;p&gt;I’ve been called in a lot as a consultant with the question, “Is the storage slowing us down? If so, what do we do?” This is really mystifying to a lot of people just because they don’t know where to look, and SQL Server gives out &lt;em&gt;so many metrics&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The good news is that this doesn’t require a whole lot of rocket science. You just need to know where to look.&lt;/p&gt;
&lt;h2 id="your-mission-show-evidence-of-when-disk-latency-impacts-performance-and-how-much-it-hurts"&gt;Your Mission: Show evidence of when disk latency impacts performance, and how much it hurts&lt;/h2&gt;
&lt;p&gt;Do your homework collecting data from the SQL Server and (sometimes, maybe) Windows.&lt;/p&gt;
&lt;p&gt;If it’s not “emergency slow”, look for potential workarounds, such as adding memory to reduce the amount of reads &amp;ndash; that’s always cheaper than speeding up storage. Take care of due diligence looking at index fixes, too.&lt;/p&gt;
&lt;p&gt;When those won’t do it, perform an analysis of exactly where faster storage would help you the most, document what it will help, and ask for help speeding up the workload.&lt;/p&gt;
&lt;p&gt;Make all of your notes and data available to the SAN admin, but write up a short TLDR summary.&lt;/p&gt;
&lt;h2 id="political-tips"&gt;Political tips&lt;/h2&gt;
&lt;p&gt;I like that you’re concerns about this already! You know this is a sensitive topic, and that things can go wrong when you bring this up.&lt;/p&gt;
&lt;p&gt;Talk about “disk latency” that you’re seeing.&lt;/p&gt;
&lt;p&gt;Some people say things like, “The SAN is slow.” That’s like the SAN admin saying, “The SQL Server is dumb.”  Things tend to go badly after you call someone’s baby ugly (whether or not the baby is actually ugly).&lt;/p&gt;
&lt;p&gt;In reality, the problem could be part of the N of SAN&amp;ndash; the network. Saying “the SAN is slow” is a really general thing, and that’s part of why it’s not really helpful. I’ve had slow storage incidents that were solved by replacing a single cable.&lt;/p&gt;
&lt;h2 id="emergency-slow---look-in-the-sql-server-error-log-for-15-second-warnings"&gt;“Emergency Slow” - Look in the SQL Server Error Log for “15 second” warnings&lt;/h2&gt;
&lt;p&gt;Filter the SQL Server log looking for messages with “longer than 15 seconds” in them.&lt;/p&gt;
&lt;p&gt;The full message is like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SQL Server has encountered [#] occurrence(s) of I/O requests taking longer than 15 seconds to complete on file [blah blah blah] in database [blah].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This message means SQL Server sent off an I/O request and waited 15 seconds (1…. 2…. 3…. ) before getting anything back.&lt;/p&gt;
&lt;p&gt;The # of occurrences is important. Was the SQL Server even doing a lot?&lt;/p&gt;
&lt;p&gt;This message will only occur once every 5 minutes, so if you see the messages repeat, the latency may have been continuous.&lt;/p&gt;
&lt;p&gt;If you see these messages, this is severe latency. Stop and send the times to the storage admins right away. Note that the SQL Server had severe storage latency at these times, and ask if any scheduled maintenance was occurring.&lt;/p&gt;
&lt;p&gt;If there was no maintenance, ask for help starting a ticket up to investigate what’s causing this. This is a severe latency problem. For the storage with the problem, start by asking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How many servers / computers share that storage&lt;/li&gt;
&lt;li&gt;How active was it at that time on the SAN side&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gather-readwrite-latency-metrics-from-sql-servers-virtual-file-stats-dynamic-management-view"&gt;Gather read/write latency metrics from SQL Server’s “virtual file stats” dynamic management view&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://msdn.microsoft.com/en-us/library/ms190326.aspx?f=255&amp;amp;MSPPError=-2147217396"&gt;Sys.dm_io_virtual_file_stats&lt;/a&gt; is your friend here!&lt;/p&gt;
&lt;p&gt;You want to know about latency when SQL Server reads from storage. This isn’t all reads, because when it can read from memory alone, it avoids the trip to storage.&lt;/p&gt;
&lt;p&gt;Look at how much is read and written to in samples &lt;em&gt;when performance is poor.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Volume of reads and writes by file (I look at MB or GB because those units make sense to me)&lt;/li&gt;
&lt;li&gt;Latency - how much are you waiting?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lots of reads but very low latency is evidence that you&amp;rsquo;re using the storage, but things are going swimmingly. And that may be the case&amp;ndash; be open to that!  The beauty of this DMV is that it can tell you if the problem is elsewhere. (If so, &lt;a href="https://kendralittle.com/2016/06/02/dear-sql-dba-lost-in-performance-troubleshooting/"&gt;start here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;This DMV reports on all physical reads, including IO done by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Backups&lt;/li&gt;
&lt;li&gt;DBCC CHECKDB&lt;/li&gt;
&lt;li&gt;Index maintenance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means that the data since start up is diluted&amp;ndash; it contains maintenance windows as well as periods of time when just not much was going on. It&amp;rsquo;s a data point, but what you really want to know is what does the data look like in 5 minute periods when performance was poor and when maintenance wasn&amp;rsquo;t running (unless your problem is slow maintenance).&lt;/p&gt;
&lt;p&gt;There are a bunch of free scripts to sample this, if you don&amp;rsquo;t feel like writing your own. Here are two:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.sqlskills.com/blogs/paul/capturing-io-latencies-period-time/"&gt;Paul Randal&amp;rsquo;s script&lt;/a&gt; from SQLSkills&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.brentozar.com/askbrent/"&gt;sp_AskBrent&lt;/a&gt; from Brent Ozar Unlimited&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="analysis-which-files-have-latency-and-is-it-acceptable"&gt;Analysis: Which files have latency, and is it acceptable?&lt;/h2&gt;
&lt;p&gt;Typically throw out samples where very few reads and writes are done. A tiny amount of reads being slow is usually not an issue.&lt;/p&gt;
&lt;p&gt;What’s impacted the most?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reads from user database data files?&lt;/li&gt;
&lt;li&gt;Writes to user database log files?&lt;/li&gt;
&lt;li&gt;Reads and writes in tempdb?&lt;/li&gt;
&lt;li&gt;Something else?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The latency numbers tell you how severe the latency is impacting you&lt;/p&gt;
&lt;p&gt;Some latency is acceptable. From Microsoft’s “&lt;a href="https://msdn.microsoft.com/en-us/library/ee410782.aspx"&gt;Analyzing I/O Characteristics and Sizing Storage Systems for SQL Server Database Applications&lt;/a&gt;”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data file latency: &amp;lt;= 20 ms (OLTP) &amp;lt;=30 ms (DW)&lt;/li&gt;
&lt;li&gt;Log files: &amp;lt;= 5 ms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are pretty aggressive targets.&lt;/p&gt;
&lt;p&gt;Your storage is not “on fire” if you see periodic 100 ms write latency to your data files.&lt;/p&gt;
&lt;p&gt;One point on writes to data files: SQL Server writes to memory and a write ahead transaction log. Seeing a 100ms insert on writes on a data file does not mean a user is waiting 100ms when inserting one row.&lt;/p&gt;
&lt;p&gt;However, seeing a 100ms read latency from a data file &lt;em&gt;may&lt;/em&gt; mean that a user is waiting on that.&lt;/p&gt;
&lt;p&gt;Things to think about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding memory frequently reduces read latency from storage for data files
&lt;ul&gt;
&lt;li&gt;Data file reads don’t have to be blazing fast when there’s sufficient memory to make reads from storage fairly rare and the workload is largely reads&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In many environments, 100 ms is tolerable as read latency. It’s all about performance standards.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Heavy write latency to transaction logs can usually only be sped up either by speeding up storage or (sometimes) changing application patterns if you’ve got a lot of tiny small commits.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Both of these options are typically somewhat expensive, unfortunately&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="helpful-cover-your-developers-butt-with-a-sanity-check-on-indexes"&gt;Helpful: Cover your (developer’s) butt with a sanity check on indexes&lt;/h2&gt;
&lt;p&gt;Arguably, storage shouldn’t be slowing you down, whether or not you have good indexes&lt;/p&gt;
&lt;p&gt;However, it&amp;rsquo;s polite to do a sanity check, because indexing can dramatically reduce the number of physical reads you do (sometimes)&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;NOTE&lt;/strong&gt;: You shouldn't have those "15 second" latency warnings in the SQL Server error log, no matter what your indexes are.
&lt;/div&gt;
&lt;p&gt;If you&amp;rsquo;ve never done an indexing health check and can request for a developer to do a quick assessment, that&amp;rsquo;s fine too&amp;ndash; you don&amp;rsquo;t have to do it yourself.&lt;/p&gt;
&lt;h2 id="sometimes-helpful-politically-gather-disk-latency-counters-from-windows"&gt;Sometimes helpful politically: Gather disk latency counters from Windows&lt;/h2&gt;
&lt;p&gt;DBAs are usually suspicious of the SAN, and SAN administrators are usually suspicious of the SQL Server.&lt;/p&gt;
&lt;p&gt;If this dynamic is a problem in your environment, Windows is kind of a neutral middle ground that helps make the SQL Server info more convincing / less threatening. It will “back up” the virtual file stats data if you need that.&lt;/p&gt;
&lt;p&gt;Latency counters on the &lt;a href="https://msdn.microsoft.com/en-us/library/ms804035.aspx?f=255&amp;amp;MSPPError=-2147217396"&gt;PhysicalDisk Object&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Physical Disk - Avg Disk sec/Read&lt;/li&gt;
&lt;li&gt;Physical Disk - Avg Disk sec/Write&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="recap"&gt;Recap!&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Talk about measured storage latency and its impact on the SQL Server. Sticking to the data points helps keep people from getting defensive / taking it personally.&lt;/li&gt;
&lt;li&gt;Look for “emergency slow” first, and triage those as a critical issue&lt;/li&gt;
&lt;li&gt;Use samples from &lt;a href="https://msdn.microsoft.com/en-us/library/ms190326.aspx?f=255&amp;amp;MSPPError=-2147217396"&gt;sys.dm_io_virtual_file_stats&lt;/a&gt; to identify if storage latency impacts you&lt;/li&gt;
&lt;li&gt;Analyze it to identify which databases are impacted, and reads vs writes&lt;/li&gt;
&lt;li&gt;Consider whether adding memory is a cheaper way to reduce the latency&lt;/li&gt;
&lt;li&gt;Remember that backups and maintenance do physical IO and will show in virtual file stats&lt;/li&gt;
&lt;li&gt;Do an indexing sanity check if possible as part of due diligence&lt;/li&gt;
&lt;li&gt;Collecting windows physical disk latency counters may help “bridge the gap” for some SAN admins&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-if-my-san-admin-doesnt-know-what-to-do"&gt;What if my SAN admin doesn’t know what to do?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Your storage vendor would love to help (for a cost) if your SAN admins aren’t sure how to troubleshoot the latency&lt;/li&gt;
&lt;li&gt;If the SAN is a recent implementation and what you’re seeing doesn’t live up to what was advertised, you may be able to get some of their time based on that difference (but your mileage will vary)&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Target Recovery Interval and Indirect Checkpoint - New Default of 60 Seconds in SQL Server 2016</title><link>https://kendralittle.com/2016/06/14/target-recovery-interval-and-indirect-checkpoint-new-default-of-60-seconds-in-sql-server-2016/</link><pubDate>Tue, 14 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/14/target-recovery-interval-and-indirect-checkpoint-new-default-of-60-seconds-in-sql-server-2016/</guid><description>&lt;p&gt;Update, 6/21/2016: Be careful using indirect checkpoint with failover clusters if your SQL Server 2014 instance is not fully patched. See &lt;a href="https://support.microsoft.com/en-us/kb/3166902"&gt;KB 3166902&lt;/a&gt;. This bug was fixed in SQL Server 2016 prior to RTM.&lt;/p&gt;
&lt;p&gt;SQL Server 2016 introduces big new features, but it also includes small improvements as well. Many of these features are described in the &lt;a href="https://blogs.msdn.microsoft.com/bobsql/tag/sql-2016/"&gt;&amp;ldquo;It Just Runs Faster&amp;rdquo; series of blog posts by Bob Ward and Bob Dorr&lt;/a&gt;.&lt;/p&gt;
&lt;figure class="alignright"&gt;&lt;img src="https://kendralittle.com/images/checkpoint-please-1024x512.png"
alt="checkpoint please" width="230"&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://blogs.msdn.microsoft.com/bobsql/2016/06/03/sql-2016-it-just-runs-faster-indirect-checkpoint-default/"&gt;One article in this series&lt;/a&gt; explained that new databases created in SQL Server 2016 will use &amp;ldquo;Indirect Checkpoint&amp;rdquo; by default. Indirect checkpoint was added in SQL Server 2012, but has not previously been enabled by default for new databases. The article emphasizes this point:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Indirect checkpoint is the recommended configuration, especially on systems with large memory footprints and default for databases created in SQL Server 2016.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Head over and &lt;a href="https://blogs.msdn.microsoft.com/bobsql/2016/06/03/sql-2016-it-just-runs-faster-indirect-checkpoint-default/"&gt;read the article to learn how indirect checkpoint works&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="indirect-checkpoint-for-new-databasesin-sql-server-2016-is-set-using-the-model-database"&gt;Indirect Checkpoint for new databases in SQL Server 2016 is set using the model database&lt;/h2&gt;
&lt;p&gt;When you create a new database in SQL Server 2016, if you use the GUI and click on the &amp;lsquo;Options&amp;rsquo; tab, you can see the &amp;ldquo;Target Recovery Time (seconds)&amp;rdquo; in the Recovery section is set to 60.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/target-recovery-interval-new-database-1.png"
alt="target-recovery-interval-new-database"&gt;
&lt;/figure&gt;
&lt;p&gt;This value is inherited from the model database, so if you don&amp;rsquo;t choose to use this as the default for your new databases, you can change it there. You can also turn this on for individual databases in SQL Server 2012, 2014, and databases restored to 2016.&lt;/p&gt;
&lt;h2 id="query-sysdatabases-to-see-your-current-recovery-interval-and-if-youre-using-indirect-checkpoint"&gt;Query sys.databases to see your current recovery interval, and if you&amp;rsquo;re using indirect checkpoint&lt;/h2&gt;
&lt;p&gt;You can see the settings for existing databases with this query&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target_recovery_time_in_seconds&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the target recovery time is set to 0, that means the database uses automatic checkpoints (not the newer indirect feature).&lt;/p&gt;
&lt;h2 id="is-60-seconds-a-big-change-in-recovery-interval"&gt;Is 60 seconds a big change in recovery interval?&lt;/h2&gt;
&lt;p&gt;Nope. Not unless you&amp;rsquo;ve changed &amp;ldquo;recovery interval (min)&amp;rdquo; in your server configuration settings. Check your current setting with this query&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value_in_use&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configurations&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;recovery interval (min)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If  your value of &amp;lsquo;recovery interval (min)&amp;rsquo; is set to zero, that means automatic checkpoints are typically occurring every minute (&lt;a href="https://msdn.microsoft.com/en-us/library/ms191154.aspx"&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Setting Target Recovery Time (Seconds) to 60 at the database level maintains the same checkpoint interval, but uses the indirect checkpoint algorithm.&lt;/p&gt;
&lt;h2 id="are-there-risks-to-using-indirect-checkpoint"&gt;Are there risks to using indirect checkpoint?&lt;/h2&gt;
&lt;p&gt;Yes. Things can go wrong with any configuration, and every setting can have bugs.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using indirect checkpoint with a failover cluster on SQL Server 2014, make sure to test and apply recent cumulative updates. On June 21, 2016, Microsoft released &lt;a href="https://support.microsoft.com/en-us/kb/3166902"&gt;KB 3166902&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This KB is a pretty serious one: &amp;ldquo;FIX: logs are missing after multiple failovers in a SQL Server 2014 failover cluster&amp;rdquo;.  When log records are missing, SQL Server can&amp;rsquo;t recover the database properly &amp;ndash; read the error message carefully in the KB and note that it says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Restore the database from a full backup, or repair the database.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;I verified from the team at Microsoft that this bug was fixed in SQL Server 2016 prior to RTM, so no need to wait for a patch.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="extra-trace-flag-3449-and-indirect-checkpoint"&gt;Extra: Trace Flag 3449 and Indirect Checkpoint&lt;/h2&gt;
&lt;p&gt;In June 2016, Microsoft released a series of Cumulative Updates for SQL Server 2012 and 2014 that recommend using Trace Flag 3449 and indirect checkpoint on servers with 2+ terabytes of memory to speed up creating new databases. &lt;a href="https://support.microsoft.com/en-us/kb/3158396"&gt;See KB 3158396 for details&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-performance-counters-should-i-monitor"&gt;What performance counters should I monitor?&lt;/h2&gt;
&lt;p&gt;Mike Ruthruff wrote an excellent blog on the SQL Server Customer Advisory Team blog  comparing performance with automatic checkpoint across several SQL Server versions with Indirect Checkpoint on SQL Server 2016.&lt;/p&gt;
&lt;p&gt;He shows how average disk write latency was lower with indirect checkpoint on the system in question, and the meaning of the &amp;ldquo;Checkpoint Pages / sec&amp;rdquo; counter (automatic checkpoints) and &amp;ldquo;Background Writer Pages/sec&amp;rdquo; counter (indirect checkpoints). &lt;a href="https://blogs.msdn.microsoft.com/sqlcat/2016/08/03/changes-in-sql-server-2016-checkpoint-behavior/"&gt;Read the post here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Next Door to Derpton - When Your Fellow DBA is a Danger to Databases (Dear SQL DBA)</title><link>https://kendralittle.com/2016/06/09/dear-sql-dba-next-door-to-derpton/</link><pubDate>Thu, 09 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/09/dear-sql-dba-next-door-to-derpton/</guid><description>&lt;p&gt;What do you do when your fellow DBA is a ticking time-bomb of bad decisions, waiting to explode your production environment?&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: This is a "listen-able" video. You can also listen to this as a podcast - learn how at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dearsqldba&lt;/a&gt;.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/u-UQr19-rqY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="heres-todays-question"&gt;Here&amp;rsquo;s Today&amp;rsquo;s Question&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;What do I do with a co-worker (who claims to have 20 years being a DBA) who puts all the production databases into Simple recovery mode?&lt;/p&gt;
&lt;p&gt;Sincerely,&lt;/p&gt;
&lt;p&gt;Next Door to Derpton&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="this-is-a-tough-one"&gt;This is a Tough One&amp;hellip;&lt;/h2&gt;
&lt;p&gt;In this case, we&amp;rsquo;re assuming that SIMPLE recovery model isn&amp;rsquo;t appropriate for all those databases&amp;mdash; and that losing all the data since the last full (or full + diff) backup might be big trouble for the business.&lt;/p&gt;
&lt;p&gt;It’s a difficult situation when one of your peers makes decisions that you feel risk the availability and safety of the data. Going deeper, it’s tough being on a team with someone who you feel doesn’t have the knowledge and skills to do their job.&lt;/p&gt;
&lt;p&gt;Especially if they might make more money than you do.&lt;/p&gt;
&lt;h2 id="you-need-protection-and-change-management-is-that-protection"&gt;You Need Protection, and Change Management is that Protection&lt;/h2&gt;
&lt;p&gt;The biggest problem is that your data may be at risk. You need to stabilize the configuration of your environment, and make sure that changes to the configuration go through a good review and approval process.&lt;/p&gt;
&lt;p&gt;This may sound like a drag, but it protects you as well. We all have those times where something that seems like a good idea backfires on us.&lt;/p&gt;
&lt;p&gt;If you don’t have Change Management, you need to become its champion. There are a lot of ways you can champion this for the sake of good process, and management typically loves it.&lt;/p&gt;
&lt;p&gt;If you do have Change Management, your mission is to make sure it’s being used well, and that when changes go wrong, you’re finding root cause.&lt;/p&gt;
&lt;h2 id="be-careful-spinning-the-wheel-of-blame"&gt;Be Careful Spinning the Wheel of Blame&lt;/h2&gt;
&lt;p&gt;Should you tell your boss that your coworker doesn’t know their transaction log from their tempdb&lt;/p&gt;
&lt;p&gt;Usually, no.&lt;/p&gt;
&lt;p&gt;If peer review is a part of your work system, it’s OK to be honest during that peer review framework. Make sure you’re being constructive.&lt;/p&gt;
&lt;p&gt;In that case, pretend it was you: you’d want to know the extent of where you needed to improve, but you wouldn’t want your nose rubbed in it.&lt;/p&gt;
&lt;p&gt;If your boss asks you what your impression is of your coworker’s skills in a private conversation, think through specific changes that have gone wrong and mention those incidents. Request that your boss keep your comments confidential.&lt;/p&gt;
&lt;p&gt;Outside of private conversations with the team manager, change the subject. You’re a team. Team dynamics that turn against one team member are bad for the whole team.&lt;/p&gt;
&lt;p&gt;If your team is having problems because of misconfigurations and changes that have gone wrong, look through those changes and make recommendations to processes to fix those.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better change review&lt;/li&gt;
&lt;li&gt;Better adherence to using change control&lt;/li&gt;
&lt;li&gt;Improving documentation on how to do things  / breaking down “knowledge silos”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s also OK to be honest about areas where you believe your team needs more training, but talk generally about the team.&lt;/p&gt;
&lt;p&gt;It takes really hard work to stay positive and keep it from getting personal in this situation, but it’s absolutely the best thing you can do.&lt;/p&gt;
&lt;p&gt;It’s bad to have a coworker who lacks skills and may put your environment at risk. It’s even worse to have them believe you’re out to get them!&lt;/p&gt;
&lt;h2 id="what-if-your-coworker-regularly-goes-off-the-ranch-and-doesnt-use-change-control"&gt;What if Your Coworker Regularly Goes Off the Ranch and Doesn’t Use Change Control?&lt;/h2&gt;
&lt;p&gt;Don’t cover for them.&lt;/p&gt;
&lt;p&gt;Ask them about it first to make sure there wasn’t an emergency change request you’re unaware of for the change, but be honest about what happened when you’re asked.&lt;/p&gt;
&lt;p&gt;In other words, treat them as an equal and a grown-up.&lt;/p&gt;
&lt;p&gt;Sometimes in this situation, people sugar coat things or cover for the person who makes mistakes. You need to treat them as an adult though.&lt;/p&gt;
&lt;p&gt;If you made mistakes, you would own up to what happened and work to not do it again, right? It’s just about respectfully allowing others to own their actions.&lt;/p&gt;
&lt;h2 id="mindset-focus-on-building-your-own-skills"&gt;Mindset: Focus on Building Your Own Skills&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s hard to stay positive in this situation. Your mindset is critical to navigating this successfully without having it drag you down.&lt;/p&gt;
&lt;p&gt;As you grow your own skills, you’re likely to work with Junior DBAs more and more.&lt;/p&gt;
&lt;p&gt;You’ll need to build strong processes, documentation, and change control to help them succeed.&lt;/p&gt;
&lt;p&gt;After working with a peer with those issues, leading Junior DBAs will seem easy, so this is awesome training for a senior level position!&lt;/p&gt;
&lt;p&gt;As often as you can, focus on your own learning and your ability to build resilient processes that help people make the right choices (and allow every change to get review and input). Because after all, that’s good for you at 3 am when the pager goes off, too.&lt;/p&gt;</description></item><item><title>Merging Boundary Points: Does a Changing Partition_Number Indicate Data Movement?</title><link>https://kendralittle.com/2016/06/07/merging-boundary-points-does-partition_number-changing-indicate-data-movement/</link><pubDate>Tue, 07 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/07/merging-boundary-points-does-partition_number-changing-indicate-data-movement/</guid><description>&lt;p&gt;I received a question from a reader who was testing out a partitioning architecture:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We are testing table partitioning using one filegroup per partition. When we merge a boundary point, we see that partition_number changes in sys.partitions. Does this mean that data movement is occurring?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short Answer:&lt;/strong&gt; Just because partition_number is changing does NOT mean there is &amp;ldquo;data movement&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better Answer&lt;/strong&gt;: You can tell for sure whether data movement  is happening in a test environment by having a script that shows how much data is in each filegroup before and after you merge! This is worth doing so you know exactly what&amp;rsquo;s going on with your setup.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take a look at the &amp;lsquo;Better Answer&amp;rsquo; here.&lt;/p&gt;
&lt;h2 id="our-test-partition-setup-the-mergethis-database"&gt;Our Test Partition Setup: the mergethis database&lt;/h2&gt;
&lt;p&gt;This script creates a testing database named merge this with an extra 10 filegroups. I&amp;rsquo;ve been irresponsible and put them on the C drive, but I bet you&amp;rsquo;re smarter than that and would never risk filling up your system drive.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mergethis&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SINGLE_USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IMMEDIATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_1.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_2.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_3.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_4.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_5.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_6.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_7.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_8.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_9.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_mergethis_10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILENAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;C:\MSSQL\DATA\fg_mergethis_10.ndf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILEGROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="now-create-a-partition-function-partition-scheme-and-a-table"&gt;Now Create a Partition Function, Partition Scheme, and a Table&lt;/h2&gt;
&lt;p&gt;Now we create a partition function named pf_merge_this, which specifies that we&amp;rsquo;re partitioning by a column with the date type. We have nine boundary points&amp;ndash; we&amp;rsquo;re partitioning by every one day. We&amp;rsquo;re using RANGE LEFT in this example.&lt;/p&gt;
&lt;p&gt;Our script then creates a partition scheme that maps each partition to a single filegroup. This is also a choice. The more filegroups you decide to use, the more complex your code becomes if you&amp;rsquo;re splitting and merging boundary points.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mergethis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf_mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-02-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-03-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-04-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-05-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-06-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-07-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-08-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-09-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps_mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf_mergethis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_1&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_2&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_3&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_4&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_5&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_6&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_7&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_8&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_9&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="n"&gt;fg_mergethis_10&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;makemeunique&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;identity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stuffnthings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;stuff&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thingsnstuff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;things&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps_mergethis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cx_mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;makemeunique&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-02-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-03-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-04-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-05-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-06-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mergetest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mypartitioningcolumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-07-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="wheres-all-our-data-lets-query-the-metadata"&gt;Where&amp;rsquo;s All Our Data? Let&amp;rsquo;s Query the Metadata&lt;/h2&gt;
&lt;p&gt;We inserted 20 rows for February 1, 30 rows for March 1, 40 rows for April 1, and so on. We can query how this is mapped to our filegroups:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;partition_function_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;partition_scheme_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary_value_on_right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;boundary_point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;row_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reserved_page_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reserved_gb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partitions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_spaces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_space_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_space_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_schemes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_space_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_space_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_functions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocation_units&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;au&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hobt_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;au&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;container_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filegroups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;au&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_space_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_space_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dm_db_partition_stats&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_number&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_range_values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary_value_on_right&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ps_mergethis&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://kendralittle.com/images/partitioning-filegroup-mapping-partition_number_1_empty-1.png"
alt="partitioning-filegroup-mapping-partition_number_1_empty"&gt;
&lt;/figure&gt;
&lt;p&gt;This all looks in order. We have a boundary point for January 1, but we didn&amp;rsquo;t insert any rows for it. It&amp;rsquo;s mapped to the fg_mergethis_1 filegroup and is currently partition_number 1.&lt;/p&gt;
&lt;h2 id="and-now-we-merge"&gt;And Now We Merge&lt;/h2&gt;
&lt;p&gt;The question I got was about merging, so let&amp;rsquo;s merge! We&amp;rsquo;re going to get rid of the January 1 Boundary Point:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pf_mergethis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MERGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RANGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2016-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Blammo, it&amp;rsquo;s gone!&lt;/p&gt;
&lt;p&gt;Rerunning our query for the metadata above, here&amp;rsquo;s what the table looks like now:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://kendralittle.com/images/partitioning-filegroup-mapping-partition_number_1_after_merge-1.png"
alt="partitioning-filegroup-mapping-partition_number_1_after_merge"&gt;
&lt;/figure&gt;
&lt;p&gt;We blew away a partition &amp;ndash; the partition mapped to fg_mergethis_1 is now totally gone. Partition_number 1 has been &lt;em&gt;reassigned&lt;/em&gt; to the partition with a boundary point of February 1.&lt;/p&gt;
&lt;p&gt;But data didn&amp;rsquo;t move when we merged the partitions in this case. There were always 20 rows in the fg_mergethis_2 filegroup.&lt;/p&gt;
&lt;p&gt;Partition_number is a logical construct. When it changes you don&amp;rsquo;t necessarily have a data movement.&lt;/p&gt;
&lt;h2 id="data-movement-matters--it-can-be-seriously-slow"&gt;Data Movement Matters &amp;ndash; It Can Be Seriously Slow&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s completely valid to be concerned about data movement. &amp;ldquo;Data movement&amp;rdquo; is just what it sounds like: data being physically moved from one partition to another. It&amp;rsquo;s fully logged and can cause a huge performance hit. If you&amp;rsquo;re planning out partitioning, you need to carefully:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decide if you&amp;rsquo;re using left or right for your partition function&lt;/li&gt;
&lt;li&gt;Decide how many filegroups you&amp;rsquo;re using (&lt;a href="https://blogs.msdn.microsoft.com/sqlserverstorageengine/2010/02/03/performance-improvement-by-orders-of-magnitude-when-merging-partitions-in-sql-server-2008r2/"&gt;it&amp;rsquo;s relevant to merge performance!&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Test out split and merge if you&amp;rsquo;re using them and examine carefully if you&amp;rsquo;re getting data movement. If you&amp;rsquo;re getting data movement, &lt;a href="https://msdn.microsoft.com/en-us/library/ms186307.aspx"&gt;re-read the section on MERGE RANGE in the documentation for ALTER PARTITION FUNCTION&lt;/a&gt; and revisit your design.&lt;/li&gt;
&lt;li&gt;Test out &lt;a href="https://kendralittle.com/2015/11/17/did-my-query-eliminate-table-partitions-sql-server/"&gt;partition elimination for your queries and make sure it behaves like you expect&lt;/a&gt; (if not, revisit your choices)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="do-you-even-need-to-merge"&gt;Do You Even Need to Merge?&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re designing partitioning, it&amp;rsquo;s always worth thinking about whether &lt;a href="http://kejser.org/table-pattern-rotating-log-ring-buffer/"&gt;a rotating log design could work for you&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Avoiding merge and split makes life easier in the long run if possible, so don&amp;rsquo;t forget this architecture when you&amp;rsquo;re in the design phase.&lt;/p&gt;</description></item><item><title>Lost in Performance Troubleshooting - Perf Triage for SQL Server</title><link>https://kendralittle.com/2016/06/02/dear-sql-dba-lost-in-performance-troubleshooting/</link><pubDate>Thu, 02 Jun 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/06/02/dear-sql-dba-lost-in-performance-troubleshooting/</guid><description>&lt;p&gt;&lt;em&gt;Psssttt &amp;ndash; I have an updated blog post on this called &lt;a href="https://kendralittle.com/2020/03/19/the-learners-guide-to-sql-server-performance-triage/"&gt;the Learner&amp;rsquo;s Guide to SQL Server Performance Tuning&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The SQL Server is slow, what should you do? I answer a reader question and share my strategy for performance troubleshooting.&lt;/p&gt;
&lt;div class="info-note"&gt;
🔥 &lt;strong&gt;Note&lt;/strong&gt;: This is a "listen-able" video. You can also listen to this as a podcast - learn how at &lt;a href="https://kendralittle.com/dearsqldba/"&gt;kendralittle.com/dearsqldba&lt;/a&gt;.
&lt;/div&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/0vX9aKhCn_4?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="this-week-our-question-is-about-troubleshooting-performance"&gt;This week, our question is about troubleshooting performance&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear SQL DBA,&lt;/p&gt;
&lt;p&gt;is there any step-by-step script that you would use to start your troubleshooting? My production SQL Server has a problem with memory pressure. Page Life Expectancy is low and lazy writes are high. I heard that Microsoft engineers will use SQL Diag then Nexus to troubleshoot, but I have not had success using those tools.&lt;/p&gt;
&lt;p&gt;Lost in Performance Troubleshooting&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="you-need-a-strategy"&gt;You need a strategy&lt;/h2&gt;
&lt;p&gt;Tools change over time - for example, Query Store is a huge new tool in SQL Server 2016 (awesome!)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Develop a strong performance troubleshooting strategy&lt;/li&gt;
&lt;li&gt;Plug tools into your strategy based on the SQL Server version, and whether you can afford a legit monitoring tool for the instance in question&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="my-performance-troubleshooting-strategy"&gt;My performance troubleshooting strategy&lt;/h2&gt;
&lt;p&gt;When things are slow, I want to know three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;What queries are running, how long have they been running, and what are they waiting on?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What are the overall waits for the time period?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And never ever skip….&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Sanity check: Am I missing anything obvious?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sanity check examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Messages in the SQL Server Error Log indicating stack dumps, corruption, failed logins&lt;/li&gt;
&lt;li&gt;Database settings where databases are automatically shrinking&lt;/li&gt;
&lt;li&gt;SQL Server settings where someone forgot to raise the Max Server Memory, or thought it was set in GB, not MB&lt;/li&gt;
&lt;li&gt;Messages in the Windows Event Log indicating power problems, failing RAM, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="why-are-wait-stats-so-important"&gt;Why are wait stats so important?&lt;/h3&gt;
&lt;p&gt;I’m recommending looking at waits in two out of three steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What’s running now and what is it waiting on?&lt;/li&gt;
&lt;li&gt;What are the overall waits?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Waits are critical to performance because it’s SQL Server’s way of explaining, “What made this slow?”&lt;/p&gt;
&lt;p&gt;Waits are overlooked because they can be confusing to decode, and it takes time to learn to interpret them.&lt;/p&gt;
&lt;p&gt;Waits are worth the effort because&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They describe slowness rather than # of whatevers per whatever. Perhaps I just don’t have more whatevers I need to do.&lt;/li&gt;
&lt;li&gt;When combined with “What’s executing now?”, waits point you in the direction of areas to look deeper and help clarify: is the whole server slow? Are one or a few queries slowing the whole server down?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="given-the-example-how-would-memory-pressure-look-with-this-approach"&gt;Given the example, how would memory pressure look with this approach?&lt;/h3&gt;
&lt;p&gt;What is running? Look at the duration and waits&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Could be a lot of shorter commands that finish quickly
&lt;ul&gt;
&lt;li&gt;If so: does a current 30 second sample of waits have much higher waits than normal?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Could be several longer commands
&lt;ul&gt;
&lt;li&gt;What are they waiting on? Is blocking making some queries slower than others?&lt;/li&gt;
&lt;li&gt;Save off the queries, execution plans, and wait information
&lt;ul&gt;
&lt;li&gt;They’ll disappear, and these are how you can sort out if the query needs an index / if the storage is slow, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What are things waiting on? In a memory pressure situation, I’d expect to see&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PAGEIOLATCH waits (usually).
&lt;ul&gt;
&lt;li&gt;If data isn’t in memory, we have to go read from storage, and this wait indicates we’re reading from storage a lot.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LCK waits (possibly)
&lt;ul&gt;
&lt;li&gt;When queries get slow, sometimes they may start keeping each other from making progress, creating a backlog&amp;ndash; that can take over memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RESOURCE_SEMAPHORE waits (sometimes) - a specific kind of memory pressure so that queries can’t even get memory grants
&lt;ul&gt;
&lt;li&gt;This may happen if there’s a big backlog of queries, or if a process is kicking off a bunch of queries that need large memory grants at once&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-if-im-not-at-the-keyboard-when-performance-is-bad"&gt;What if I&amp;rsquo;m not at the keyboard when performance is bad?&lt;/h2&gt;
&lt;p&gt;You can’t always be there when the SQL Server is slow.&lt;/p&gt;
&lt;p&gt;Plus, you need a baseline of waits. (This is hard enough without knowing what’s normal!)&lt;/p&gt;
&lt;p&gt;Specialized SQL Server monitoring tools collect wait information.&lt;/p&gt;
&lt;p&gt;There’s also free tools out there you can use, but you need to make sure you don’t impact the system too much.&lt;/p&gt;
&lt;h2 id="free-sql-server-performance-troubleshooting-tools"&gt;Free SQL Server performance troubleshooting tools&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Several fine paid vendor tools work to provide all of these things for you in one interface. I’m talking about the free ones here.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Waits Reference - Paul Randal’s SQL Server Wait Library: &lt;a href="https://www.sqlskills.com/help/waits/"&gt;https://www.sqlskills.com/help/waits/&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What queries are running, how long have they been running, and what are they waiting on?&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;sp_WhoIsActive by Adam Machanic - &lt;a href="http://sqlblog.com/files/default.aspx"&gt;http://sqlblog.com/files/default.aspx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;This can be used to log information to a table - &lt;a href="https://kendralittle.com/2011/02/01/whoisactive/"&gt;/2011/02/01/whoisactive/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;What are the overall waits for the time period? (You only really need one of these tools, but try them out and see which you like best.)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Paul Randal’s script - &lt;a href="http://www.sqlskills.com/blogs/paul/capturing-wait-statistics-period-time/"&gt;http://www.sqlskills.com/blogs/paul/capturing-wait-statistics-period-time/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Brent Ozar Unlimited’s sp_AskBrent - &lt;a href="https://www.brentozar.com/askbrent/"&gt;https://www.brentozar.com/askbrent/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Sanity check: Am I missing anything obvious? (You only really need one of these tools, but try them out and see which you like best.)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Brent Ozar Unlimited’s sp_Blitz script: &lt;a href="https://www.brentozar.com/blitz/"&gt;https://www.brentozar.com/blitz/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Glenn Berry’s Diagnostic Information Queries: &lt;a href="http://www.sqlskills.com/blogs/glenn/category/dmv-queries/"&gt;http://www.sqlskills.com/blogs/glenn/category/dmv-queries/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-will-sql-server-2016-change-this"&gt;How will SQL Server 2016 change this?&lt;/h2&gt;
&lt;p&gt;The new &lt;a href="https://kendralittle.com/tags/query-store/"&gt;Query Store feature&lt;/a&gt; doesn’t collect wait statistics&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;However, it does collect what was running, how long it was running, and what the plan was&lt;/li&gt;
&lt;li&gt;This is very powerful&lt;/li&gt;
&lt;li&gt;Wait statistics remain important&amp;ndash; to collect to decode what’s making things slow, but Query Store will become the “new best friend” of wait stats&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And hey, who knows if Query Store might start to collect waits as well in the future … or if it might have a Wait Store friend? (No secret knowledge here, just a wish&amp;hellip; because that would be awesome.)&lt;/p&gt;</description></item><item><title>Testing an Insert for Race Conditions with Ostress.exe</title><link>https://kendralittle.com/2016/05/31/testing-an-insert-for-race-conditions-with-ostress-exe/</link><pubDate>Tue, 31 May 2016 00:00:00 +0000</pubDate><author>help@KendraLittle.com (Kendra Little)</author><guid>https://kendralittle.com/2016/05/31/testing-an-insert-for-race-conditions-with-ostress-exe/</guid><description>&lt;p&gt;Whenever we have multiple sessions modifying data, things get tricky. When we have a pattern of &amp;ldquo;check if the data exists and then do a thing,&amp;rdquo; multiple sessions get even more complicated.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not very practical to try to open a bunch of sessions in SQL Server Management Studio to run commands in a loop. It&amp;rsquo;s hard to manage and if you&amp;rsquo;re like me, you find a way to crash SSMS doing it.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s much easier to test for race conditions using the free OStress.exe tool from Microsoft. &lt;a href="https://www.microsoft.com/en-us/download/details.aspx?id=4511"&gt;Download OStress.exe as part of the RML Utilities for SQL Server (x64) here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="our-example-insert-a-row-if-it-doesnt-exist-already"&gt;Our Example: Insert a Row if It Doesn&amp;rsquo;t Exist Already&lt;/h2&gt;
&lt;p&gt;We have a simple table named dbo.RaceCondition with two columns: RaceConditionId and RaceConditionValue. RaceConditionId is the clustered Primary Key. A unique index on RaceConditionValue prevents duplicate rows from being inserted.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how to create it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DB_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;RaceConditionTesting&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MASTER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RaceConditionTesting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SINGLE_USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IMMEDIATE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RaceConditionTesting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RaceConditionTesting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RaceConditionTesting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RaceConditionTable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RaceConditionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RaceConditionValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pk_RaceConditionTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CLUSTERED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RaceConditionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ix_RaceConditionTable_RaceConditionValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RaceConditionTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RaceConditionValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Insert one row */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RaceConditionTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RaceConditionValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="our-first-attempt-a-single-select-statement"&gt;Our First Attempt: A Single Select Statement&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the code to insert rows into dbo.RaceConditionTable. dbo.InsertIfNotExists contains just one INSERT/SELECT statement.&lt;/p&gt;
&lt;p&gt;Note that this is all one statement. There&amp;rsquo;s no &amp;ldquo;IF&amp;rdquo; statement. There&amp;rsquo;s also no hints.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dbo.InsertIfNotExists&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXEC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;CREATE PROCEDURE dbo.InsertIfNotExists as RETURN 0;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsertIfNotExists&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;RaceConditionValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOCOUNT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RaceC