<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>wiseDATAman</title><link>https://wisedataman.com/</link><description>SQL Server &amp; SysAdmin, Blog, Tools &amp; Scripts</description><language>en-gb</language><lastBuildDate>Tue, 13 May 2025 21:52:33 +0000</lastBuildDate><atom:link href="https://wisedataman.com/index.xml" rel="self" type="application/rss+xml"/><item><title>T-SQL Tuesday #186 - Managing Agent Jobs</title><link>https://wisedataman.com/t-sql-tuesday-186-managing-agent-jobs/</link><pubDate>Tue, 13 May 2025 21:52:33 +0000</pubDate><guid>https://wisedataman.com/t-sql-tuesday-186-managing-agent-jobs/</guid><description>&lt;figure class="wp-block-image alignleft size-full is-resized is-style-default"&gt;&lt;a href="https://www.flxsql.com/2025/05/06/t-sql-tuesday-186-managing-agent-jobs-invite/"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image.png" alt="T-SQL Tuesday Logo" class="wp-image-734" style="width:154px;height:auto" loading="lazy"&gt;&lt;/a&gt;&lt;/figure&gt;&#10;&lt;p&gt;For T-SQL Tuesday #186, &lt;a href="https://www.flxsql.com/2025/05/06/t-sql-tuesday-186-managing-agent-jobs-invite/"&gt;Andy Levy asks&lt;/a&gt;, &lt;em&gt;&amp;ldquo;How do you manage and/or monitor your SQL Server Agent jobs?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;This is a great opportunity for me to discuss how &lt;a href="https://dbadash.com/"&gt;DBA Dash&lt;/a&gt; can help monitor SQL Agent jobs. DBA Dash is a free and &lt;strong&gt;&lt;a href="https://github.com/trimble-oss/dba-dash"&gt;open-source&lt;/a&gt;&lt;/strong&gt; monitoring tool for SQL Server, created by me. It&amp;rsquo;s used to monitor thousands of SQL Server instances within Trimble alone, and it&amp;rsquo;s gaining popularity in the SQL Server community.&lt;/p&gt;&#10;&lt;h2 id="built-in-alerts-for-job-failures"&gt;Built-in alerts for job failures&lt;/h2&gt;&#10;&lt;p&gt;Before we discuss DBA Dash, what can we do within SQL Server without any 3rd party tools?&lt;/p&gt;&#10;&lt;p&gt;SQL Agent jobs have native alert notifications. You can get an email whenever a job fails, succeeds, or completes.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-1.png" alt="SQL Server agent job alert notification" class="wp-image-735" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;h3 id="issues-with-built-in-alerts"&gt;Issues with built-in alerts:&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;If a frequently executed job starts failing, this can generate a lot of noise.&lt;br&gt;&#10;&lt;em&gt;A workaround is to set a retry policy and retry interval for your job steps.&lt;/em&gt;&lt;/li&gt;&#10;&lt;li&gt;A lack of a failure notification doesn&amp;rsquo;t mean that everything is in a good state.&lt;br&gt;&#10;&lt;em&gt;You should validate the status of your SQL agent jobs in combination with alerts. Job activity monitor in SSMS could be used for this, but it doesn&amp;rsquo;t scale if you have many SQL instances to monitor.&lt;/em&gt;&lt;/li&gt;&#10;&lt;li&gt;It requires database mail. There are no modern notification channels like Slack, Google chat, PagerDuty etc.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="dba-dash"&gt;DBA Dash&lt;/h2&gt;&#10;&lt;p&gt;DBA Dash includes several useful features to help you monitor your SQL Agent jobs.&lt;/p&gt;&#10;&lt;h3 id="summary-page"&gt;Summary page&lt;/h3&gt;&#10;&lt;p&gt;First up is the summary page. This is a single-page report that can tell you if you have failing jobs across your whole SQL Server estate. It can also tell you if your SQL Server agent is stopped on any of those instances. The summary page includes &lt;strong&gt;many&lt;/strong&gt; other things you should include as part of your &lt;strong&gt;daily checks&lt;/strong&gt;, in addition to monitoring agent jobs.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-2-1024x549.png" alt="DBA Dash daily checks summary page" class="wp-image-737" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;From the summary page, you can drill down and see specific jobs that are failing across your instances. You can click to view the failed steps and messages.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-3-1024x266.png" alt="" class="wp-image-738" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;Thresholds and exclusions can be configured at the root, instance or job level.&lt;/p&gt;&#10;&lt;h3 id="alerts"&gt;Alerts&lt;/h3&gt;&#10;&lt;p&gt;DBA Dash has an AgentJob alert rule that you can use for instant notifications. You can target a specific server, a group of servers (using tags), and filter by category and job name. Your notification options currently include Email, Slack, PagerDuty and Webhook (e.g. Google Chat).&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-11-1024x169.png" alt="Slack alert notification" class="wp-image-746" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;This provides more modern notification options over built-in alerts and allows alerts to be configured centrally. You can control when you are notified and by what mechanism, depending on the priority of the alert.&lt;/p&gt;&#10;&lt;h3 id="job-performance"&gt;Job Performance&lt;/h3&gt;&#10;&lt;p&gt;You might also be interested in tracking job performance over time. DBA Dash allows you to do this centrally. The msdb database maintains a history of job execution, but the DBA Dash repository database enables you to store the execution metrics for a long time with minimal storage cost. You can also visualize the job performance over time very easily.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-4-1024x509.png" alt="SQL Server agent job performance over time" class="wp-image-739" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;h3 id="timeline"&gt;Timeline&lt;/h3&gt;&#10;&lt;p&gt;The timeline view is a great way to see which jobs ran when and how long they ran for. This is useful to help plan job schedules, among other things.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-5-1024x294.png" alt="SQL Server agent job timeline view" class="wp-image-740" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;h3 id="running-jobs"&gt;Running Jobs&lt;/h3&gt;&#10;&lt;p&gt;Want to know what jobs are running right now across all your instances?&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-6-1024x195.png" alt="" class="wp-image-741" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;h3 id="schema-tracking"&gt;Schema Tracking&lt;/h3&gt;&#10;&lt;p&gt;DBA Dash scripts your SQL agent jobs, tracking when changes occur. This can be used to help answer what changed when and provides access to previous versions of jobs, should you need to roll back.&lt;/p&gt;&#10;&lt;p&gt;If you can source control your SQL agent jobs, that is also a great idea. DBA Dash can complement that.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-7-1024x556.png" alt="SQL Agent job schema tracking" class="wp-image-742" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;This feature is also used to provide a SQL agent job DIFF tool so you can compare jobs between SQL instances.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-8-1024x665.png" alt="SQL Server agent job compare servers" class="wp-image-743" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;h3 id="more-to-come"&gt;More to come&lt;/h3&gt;&#10;&lt;p&gt;As I&amp;rsquo;m writing this, I&amp;rsquo;m working on a Job Info page to provide job details on a single page (Steps, schedules, and other metadata). I&amp;rsquo;m using ScriptDom to parse this information, and with the DDL tracking, I can display this info for past versions of a job. I can also use this to display an alternative DIFF format.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-9-1024x676.png" alt="SQL agent job info compare" class="wp-image-744" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;DBA Dash includes a Running Query capture for performance monitoring (similar to sp_WhoIsActive or sp_BlitzWho). This will show you the job name if a query is associated with a running job. In the next version of DBA Dash, this will be a link, providing you with immediate access to the job details and execution stats.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2025/05/image-10-1024x950.png" alt="SQL Server agent job info from running queries." class="wp-image-745" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;&lt;del&gt;These features should make their way into the next version of DBA Dash, 3.23. Or they might already be available by the time you read this.&lt;/del&gt;&lt;/p&gt;&#10;&lt;p&gt;Edit: 3.23 is here now! 🚀&lt;/p&gt;&#10;&lt;p&gt;Thanks for reading!&lt;/p&gt;&#10;</description></item><item><title>Removing large backup history with sp_delete_backuphistory</title><link>https://wisedataman.com/removing-large-backup-history-with-sp_delete_backuphistory/</link><pubDate>Sun, 04 Feb 2024 15:04:57 +0000</pubDate><guid>https://wisedataman.com/removing-large-backup-history-with-sp_delete_backuphistory/</guid><description>&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;&#10;&lt;p&gt;In SQL Server, the &lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-delete-backuphistory-transact-sql?view=sql-server-ver16"&gt;sp_delete_backuphistory&lt;/a&gt; stored procedure is is the standard and supported method to purge old data from the backup and restore history tables in the msdb database:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;backupfile&lt;/li&gt;&#10;&lt;li&gt;backupfilegroup&lt;/li&gt;&#10;&lt;li&gt;backupmediafamily&lt;/li&gt;&#10;&lt;li&gt;backupmediaset&lt;/li&gt;&#10;&lt;li&gt;backupset&lt;/li&gt;&#10;&lt;li&gt;restorefile&lt;/li&gt;&#10;&lt;li&gt;restorefilegroup&lt;/li&gt;&#10;&lt;li&gt;restorehistory&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Recently, I encountered an issue running sp_delete_backuphistory on servers that hosted a &lt;strong&gt;large number of databases&lt;/strong&gt; with &lt;strong&gt;frequent log backup &amp;amp; restore operations&lt;/strong&gt;. The clean up task hadn&amp;rsquo;t been scheduled and the history tables had &lt;strong&gt;grown very large over several months&lt;/strong&gt;. The msdb databases was also hosted on a &lt;strong&gt;volume with limited IOPs&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;Attempting to run sp_delete_backuphistory under these conditions you will likely encounter these issues:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;The operation will take a long time&lt;/li&gt;&#10;&lt;li&gt;Log backup and restore operations are blocked during the process&lt;/li&gt;&#10;&lt;li&gt;Your msdb log file will grow large if you try to remove too much data at once&lt;/li&gt;&#10;&lt;li&gt;If you kill off the process at any point, the whole thing will rollback.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;The sp_delete_backuphistory stored procedure gets the job done in most cases but it&amp;rsquo;s not very well optimized if you have a large amount of history to clear.&lt;/p&gt;&#10;&lt;h2 id="optimized-solution-for-backup-history-cleanup"&gt;Optimized Solution for Backup History Cleanup&lt;/h2&gt;&#10;&lt;p&gt;To clear a large amount of history without resorting to schema modifications or unsupported methods we can take an incremental approach to removing data.&lt;/p&gt;&#10;&lt;p&gt;The script below will check how much retention we currently have. It will then call sp_delete_backuphistory in a loop, removing data 1hr (&lt;em&gt;configurable&lt;/em&gt;) at a time until we hit the target retention. We can also specify a maximum runtime for the process.&lt;/p&gt;&#10;&lt;p&gt;This approach won&amp;rsquo;t necessarily speed things up but it provides the following benefits:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Data is cleared as a series of smaller transactions rather than a single large transaction&lt;/li&gt;&#10;&lt;li&gt;Smaller transactions allow for log truncation and prevent the log file from growing.&lt;/li&gt;&#10;&lt;li&gt;We can interrupt the process without having to rollback all the progress that has been made. (just the current batch)&lt;/li&gt;&#10;&lt;li&gt;Log backups/restores might still be blocked, but only for the duration it takes to complete a single loop - not for the entire time it takes to clear the history. &lt;em&gt;This can still impact RPO/RTO though.&lt;/em&gt;&lt;/li&gt;&#10;&lt;li&gt;We can control how long the process runs for. We can keep it running outside business hours or allow for breaks to prevent log backup/restores from falling too far behind.&lt;/li&gt;&#10;&lt;li&gt;The script will print progress information.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;span class="lnt"&gt;36&#10;&lt;/span&gt;&lt;span class="lnt"&gt;37&#10;&lt;/span&gt;&lt;span class="lnt"&gt;38&#10;&lt;/span&gt;&lt;span class="lnt"&gt;39&#10;&lt;/span&gt;&lt;span class="lnt"&gt;40&#10;&lt;/span&gt;&lt;span class="lnt"&gt;41&#10;&lt;/span&gt;&lt;span class="lnt"&gt;42&#10;&lt;/span&gt;&lt;span class="lnt"&gt;43&#10;&lt;/span&gt;&lt;span class="lnt"&gt;44&#10;&lt;/span&gt;&lt;span class="lnt"&gt;45&#10;&lt;/span&gt;&lt;span class="lnt"&gt;46&#10;&lt;/span&gt;&lt;span class="lnt"&gt;47&#10;&lt;/span&gt;&lt;span class="lnt"&gt;48&#10;&lt;/span&gt;&lt;span class="lnt"&gt;49&#10;&lt;/span&gt;&lt;span class="lnt"&gt;50&#10;&lt;/span&gt;&lt;span class="lnt"&gt;51&#10;&lt;/span&gt;&lt;span class="lnt"&gt;52&#10;&lt;/span&gt;&lt;span class="lnt"&gt;53&#10;&lt;/span&gt;&lt;span class="lnt"&gt;54&#10;&lt;/span&gt;&lt;span class="lnt"&gt;55&#10;&lt;/span&gt;&lt;span class="lnt"&gt;56&#10;&lt;/span&gt;&lt;span class="lnt"&gt;57&#10;&lt;/span&gt;&lt;span class="lnt"&gt;58&#10;&lt;/span&gt;&lt;span class="lnt"&gt;59&#10;&lt;/span&gt;&lt;span class="lnt"&gt;60&#10;&lt;/span&gt;&lt;span class="lnt"&gt;61&#10;&lt;/span&gt;&lt;span class="lnt"&gt;62&#10;&lt;/span&gt;&lt;span class="lnt"&gt;63&#10;&lt;/span&gt;&lt;span class="lnt"&gt;64&#10;&lt;/span&gt;&lt;span class="lnt"&gt;65&#10;&lt;/span&gt;&lt;span class="lnt"&gt;66&#10;&lt;/span&gt;&lt;span class="lnt"&gt;67&#10;&lt;/span&gt;&lt;span class="lnt"&gt;68&#10;&lt;/span&gt;&lt;span class="lnt"&gt;69&#10;&lt;/span&gt;&lt;span class="lnt"&gt;70&#10;&lt;/span&gt;&lt;span class="lnt"&gt;71&#10;&lt;/span&gt;&lt;span class="lnt"&gt;72&#10;&lt;/span&gt;&lt;span class="lnt"&gt;73&#10;&lt;/span&gt;&lt;span class="lnt"&gt;74&#10;&lt;/span&gt;&lt;span class="lnt"&gt;75&#10;&lt;/span&gt;&lt;span class="lnt"&gt;76&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-tsql" data-lang="tsql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/********************* Params *******************/&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@RetentionDays&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;INT&lt;/span&gt;&lt;span class="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;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* How long should we keep the data for in days */&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Mins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;INT&lt;/span&gt;&lt;span class="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="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Delete data X minutes at a time. Small interval keeps transaction short. Less blocking and log usage*/&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@MaxRuntimeMins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;INT&lt;/span&gt;&lt;span class="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="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Stop processing if runtime exceeds this threshold */&lt;/span&gt;&lt;span class="w"&gt;&#10;&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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@TargetDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DATETIME&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DATETIME&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&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;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DATETIME&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Duration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;INT&lt;/span&gt;&lt;span class="w"&gt;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@TotalDuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;BIGINT&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;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;INT&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;&#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;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@StopAt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DATETIME&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&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 target date we want to get to based on the specified @RetentionDays */&lt;/span&gt;&lt;span class="w"&gt;&#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;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@TargetDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;@RetentionDays&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* When should we stop processing batches based on @MaxRuntimeMins */&lt;/span&gt;&lt;span class="w"&gt;&#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;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@StopAt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@MaxRuntimeMins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&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 the oldest backup finish date from table. We will start removing data older than this point + @Mins minutes */&lt;/span&gt;&lt;span class="w"&gt;&#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;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_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="nf"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backup_finish_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#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;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msdb&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;backupset&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#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;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Oldest Date: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#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;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Target Date: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@TargetDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#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;PRINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Max Run Time (Mins): &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@MaxRuntimeMins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;, Processing will stop after &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@StopAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* Process the delete operation in small chunks until we reach the target date for our retention */&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&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="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="cm"&gt;/* Increment date by @Mins minutes */&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_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="nf"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@Mins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="cm"&gt;/* Ensure that we don&amp;#39;t overshoot our target date */&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&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="nv"&gt;@TargetDate&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_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="nv"&gt;@TargetDate&lt;/span&gt;&lt;span class="w"&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&lt;/span&gt;&lt;span class="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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="cm"&gt;/* &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;&#9;Print message using RAISERROR WITH NOWAIT so message is printed immediately. &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;&#9;For keeping track of progress &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;&#9;*/&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="mi"&gt;114&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; Start iteration &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;: Removing backup history before &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@Message&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 class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOWAIT&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;SYSUTCDATETIME&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="cm"&gt;/* Remove the history up to @oldest_date (@Mins minutes worth of history) */&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&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;msdb&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;sp_delete_backuphistory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_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="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="cm"&gt;/* Print how long this iteration took &amp;amp; keep track of total duration and iteration count */&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@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="nf"&gt;DATEDIFF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;SYSUTCDATETIME&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@TotalDuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@TotalDuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Duration&lt;/span&gt;&lt;span class="w"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="mi"&gt;114&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; Iteration &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; completed in (hh:mi:ss:mmm): &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@Duration&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;114&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@Message&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 class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOWAIT&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="cm"&gt;/* Stop once we hit our target date for retention or we have ran for longer than @MaxRuntimeMins */&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt;@TargetDate&lt;/span&gt;&lt;span class="w"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&lt;/span&gt;&lt;span class="ow"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;GETDATE&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="nv"&gt;@StopAt&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&lt;/span&gt;&lt;span class="k"&gt;BREAK&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&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;/* &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;&#9;Print overall stats &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;&#9;Accounting for possibility that total duration could span &amp;gt; 1 day&#10;&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;&#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;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Completed &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; iterations in &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="nf"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;DATEDIFF&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;DATEADD&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="nv"&gt;@TotalDuration&lt;/span&gt;&lt;span class="o"&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="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;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&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="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; Days &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="nf"&gt;LEFT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;DATEADD&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="nv"&gt;@TotalDuration&lt;/span&gt;&lt;span class="o"&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="mi"&gt;114&lt;/span&gt;&lt;span class="p"&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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; (hh:mi:ss), Avg Duration: &amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;CONVERT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;@TotalDuration&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@IterationCount&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;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;114&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#9;&#9;&#9;&#9;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; (hh:mi:ss:mmm). Reached target date: &amp;#39;&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="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@oldest_date&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt;@TargetDate&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;YES&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;NO&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="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#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;RAISERROR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@Message&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 class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOWAIT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;h2 id="links"&gt;Links:&lt;/h2&gt;&#10;&lt;p&gt;These related links might be interesting:&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://www.brentozar.com/archive/2018/02/the-annals-of-hilariously-bad-code-part-1/"&gt;https://www.brentozar.com/archive/2018/02/the-annals-of-hilariously-bad-code-part-1/&lt;/a&gt;&lt;br&gt;&#10;&lt;a href="https://www.brentozar.com/archive/2018/02/annals-hilariously-bad-code-part-2/"&gt;https://www.brentozar.com/archive/2018/02/annals-hilariously-bad-code-part-2/&lt;/a&gt;&lt;br&gt;&#10;&lt;a href="https://dba.stackexchange.com/questions/233375/how-to-minimize-plan-ahead-the-effect-of-running-sp-delete-backuphistory-measur"&gt;https://dba.stackexchange.com/questions/233375/how-to-minimize-plan-ahead-the-effect-of-running-sp-delete-backuphistory-measur&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>T-SQL Tuesday #156 Production Code</title><link>https://wisedataman.com/t-sql-tuesday-156-production-code/</link><pubDate>Tue, 08 Nov 2022 08:31:01 +0000</pubDate><guid>https://wisedataman.com/t-sql-tuesday-156-production-code/</guid><description>&lt;figure class="wp-block-image aligncenter size-thumbnail"&gt;&lt;a href="https://straightforwardsql.com/posts/production-code/"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/MJTuesday-150x150.png" alt="" class="wp-image-675" loading="lazy"&gt;&lt;/a&gt;&lt;/figure&gt;&#10;&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;&#10;&lt;p&gt;The &lt;a href="https://straightforwardsql.com/posts/production-code/"&gt;invitation&lt;/a&gt; from &lt;a href="https://straightforwardsql.com/about/"&gt;Tom Zíka&lt;/a&gt; asks &amp;ldquo;&lt;strong&gt;Which quality makes code production grade?&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;&#10;&lt;h2 id="reliability"&gt;Reliability&lt;/h2&gt;&#10;&lt;p&gt;Code that runs in production should be reliable. It should produce consistent results, handle concurrency and deal with error situations.&lt;/p&gt;&#10;&lt;h2 id="performance--scalability"&gt;Performance &amp;amp; Scalability&lt;/h2&gt;&#10;&lt;p&gt;Production code needs to be able to scale. Scalability should be considered in the context of your own applications and their expected growth. Not everyone has to deal with the same scalability challenges as Google, Facebook or Twitter.&lt;/p&gt;&#10;&lt;p&gt;Performance is also important. It doesn&amp;rsquo;t matter how awesome your app is if it can&amp;rsquo;t return data fast enough for end users.&lt;/p&gt;&#10;&lt;p&gt;Fast and efficient code can save $$$ in running costs and keep end users happy.&lt;/p&gt;&#10;&lt;h2 id="security"&gt;Security&lt;/h2&gt;&#10;&lt;p&gt;Production code needs to be secure, following industry best practices. A security incident can cause severe reputational damage and financial impact.&lt;/p&gt;&#10;&lt;h2 id="maintainability"&gt;Maintainability&lt;/h2&gt;&#10;&lt;p&gt;Production code should be maintainable. Avoiding duplication and striving for simplicity.&lt;/p&gt;&#10;&lt;h2 id="reviewed"&gt;Reviewed&lt;/h2&gt;&#10;&lt;p&gt;Production code will often go through a code review by another developer before it&amp;rsquo;s accepted into the codebase.&lt;/p&gt;&#10;&lt;h2 id="tested"&gt;Tested&lt;/h2&gt;&#10;&lt;p&gt;Production code will go through a series of automated and human tests before it gets to production.&lt;/p&gt;&#10;&lt;h2 id="accurate"&gt;Accurate?&lt;/h2&gt;&#10;&lt;p&gt;Production code &lt;strong&gt;doesn&amp;rsquo;t&lt;/strong&gt; always have to produce accurate results. Accuracy can be very important in some situations. In others, you might be able to trade some accuracy for speed. e.g. Caching data, eventual consistency.&lt;br&gt;&#10;The number of active users on a website doesn&amp;rsquo;t need to be 100% accurate and can be out of date by the time it&amp;rsquo;s printed.&lt;/p&gt;&#10;&lt;h2 id="documented"&gt;Documented&lt;/h2&gt;&#10;&lt;p&gt;Production code should have comments and documentation.&lt;/p&gt;&#10;&lt;h2 id="other"&gt;Other&lt;/h2&gt;&#10;&lt;p&gt;You might have policies for coding standards to follow. This might include things like naming conventions, code formatting and other best practices.&lt;/p&gt;&#10;&lt;h2 id="does-it-need-to-be-perfect"&gt;Does it need to be perfect?&lt;/h2&gt;&#10;&lt;p&gt;Production code &lt;strong&gt;doesn&amp;rsquo;t&lt;/strong&gt; have to be perfect. Perfect code doesn&amp;rsquo;t really exist. The code we write today will be viewed through a different lens tomorrow with the benefit of hindsight, experience and new improved ways of doing things.&lt;/p&gt;&#10;&lt;p&gt;The code we ship to production needs to be fit for purpose. Shipping code that works and delivers value in a timely manner is often more important than spending months trying to find the most optimal solution. There is a balance to be struck.&lt;/p&gt;&#10;&lt;p&gt;Architectural decisions made early in a project can have long-lasting consequences. Making good decisions early in a project can be cheaper than fixing them later.&lt;/p&gt;&#10;&lt;p&gt;You can&amp;rsquo;t always predict how users will use a new feature and how to optimize it. Growing pains are inevitable for successful applications. It&amp;rsquo;s important to monitor and be proactive in fixing problems.&lt;/p&gt;&#10;&lt;h2 id="not-production-grade"&gt;Not production grade&lt;/h2&gt;&#10;&lt;p&gt;So what are some examples of code that shouldn&amp;rsquo;t be in production?&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Code that uses undocumented/unsupported features or behaviour&lt;/li&gt;&#10;&lt;li&gt;Untested code&lt;/li&gt;&#10;&lt;li&gt;Insecure code. e.g. Building dynamic SQL in a way that is prone to SQL injection.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;&#10;&lt;p&gt;Production code can vary in quality for a variety of reasons. The experience level of the developer writing the code, time pressures, and level of fatigue all impact code quality.&lt;/p&gt;&#10;&lt;p&gt;It&amp;rsquo;s not unusual for code written as a quick PoC to find its way into production. Code can also start to get messy over time as you start to shoehorn new features into an existing codebase.&lt;/p&gt;&#10;&lt;p&gt;If your code is delivering value to the end-user or business you can feel happy about it. Over time we all accumulate technical debt and need to allocate time to reduce it.&lt;/p&gt;&#10;</description></item><item><title>Speaking at Data Relay</title><link>https://wisedataman.com/speaking-at-data-relay/</link><pubDate>Thu, 13 Oct 2022 12:17:23 +0000</pubDate><guid>https://wisedataman.com/speaking-at-data-relay/</guid><description>&lt;p&gt;&lt;a href="https://datarelay.co.uk/"&gt;Data Relay&lt;/a&gt; is a free community conference in the UK for the Microsoft data platform. I submitted a session for DBA Dash which was accepted and I delivered my session on the 4th October 2022 in Leeds.&lt;/p&gt;&#10;&lt;p&gt;This was the first time I&amp;rsquo;ve done something like this and it was outside of my comfort zone. I was excited to show off DBA Dash though. My plan was to demo how to use the tool to solve performance issues.&lt;/p&gt;&#10;&lt;p&gt;I created demos in my Lab environment and restored the repository database to my laptop to perform the demos.&lt;/p&gt;&#10;&lt;p&gt;To help prepare for speaking at data relay I recorded myself. This allowed my to practice my presentation and get an idea how long it would take to deliver. The actual session at data relay wasn’t recorded but I’ve uploaded my practice session to YouTube. It’s a bit rough around the edges, but hopefully you will find the &lt;a href="https://www.youtube.com/watch?v=pGro__GkeDM"&gt;video&lt;/a&gt; useful. 😊&lt;/p&gt;&#10;&lt;figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"&gt;&lt;div class="wp-block-embed__wrapper"&gt;https://youtu.be/pGro__GkeDM&lt;/div&gt;&lt;/figure&gt;&#10;&lt;p&gt;Thank you to &lt;a href="https://twitter.com/MrKeithAtherton"&gt;&lt;/a&gt;&lt;a href="https://twitter.com/MrKeithAtherton"&gt;@MrKeithAtherton&lt;/a&gt; for providing the photo from the event!&lt;/p&gt;&#10;</description></item><item><title>What's new in 2.23.0</title><link>https://wisedataman.com/whats-new-in-2-23-0/</link><pubDate>Mon, 10 Oct 2022 15:54:37 +0000</pubDate><guid>https://wisedataman.com/whats-new-in-2-23-0/</guid><description>&lt;h2 id="os-loaded-modules-reporting"&gt;OS Loaded Modules Reporting&lt;/h2&gt;&#10;&lt;p&gt;Some modules such as antivirus software are known to cause issues when loaded into SQL Server address space. These problems might vary from performance issues to weird bugs and corruption. DBA Dash can now highlight where you have problematic modules loaded.&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://dbadash.com/docs/help/os-loaded-modules/"&gt;Read more here&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>New website for DBA Dash!</title><link>https://wisedataman.com/new-website-for-dba-dash/</link><pubDate>Sun, 02 Oct 2022 13:43:57 +0000</pubDate><guid>https://wisedataman.com/new-website-for-dba-dash/</guid><description>&lt;p&gt;DBA Dash has a &lt;a href="https://dbadash.com"&gt;new website&lt;/a&gt;. The purpose of this site is to provide a friendly landing page for new users of DBA Dash and to provide a better documentation experience.&lt;/p&gt;&#10;&lt;p&gt;DBA Dash remains open source and the &lt;a href="https://github.com/trimble-oss/dba-dash"&gt;GitHub page&lt;/a&gt; isn&amp;rsquo;t going anywhere. GitHub is still the place to log issues, create discussions and contribute to the project.&lt;/p&gt;&#10;&lt;p&gt;I hope you like the new website and find the documentation easier to navigate. I want to improve the documentation experience over time.&lt;/p&gt;&#10;&lt;p&gt;The &lt;a href="https://dbadash.com"&gt;dbadash.com&lt;/a&gt; website was created with &lt;a href="https://getdoks.org/"&gt;Doks&lt;/a&gt;. Doks is a theme for &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, a static website generator. This the first time I&amp;rsquo;ve used a static site generator. There is a bit of a learning curve compared to something like WordPress. Static websites are fast, easy to source control and cheaper to host though.&lt;/p&gt;&#10;</description></item><item><title>T-SQL Tuesday #154 Invitation – SQL Server 2022</title><link>https://wisedataman.com/t-sql-tuesday-154/</link><pubDate>Tue, 13 Sep 2022 08:03:38 +0000</pubDate><guid>https://wisedataman.com/t-sql-tuesday-154/</guid><description>&lt;div class="wp-block-image"&gt;&lt;figure class="aligncenter"&gt;&lt;a href="https://glennsqlperformance.com/2022/09/05/t-sql-tuesday-154-invitation-sql-server-2022/"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/MJTuesday-150x150.png" alt="" class="wp-image-675" loading="lazy"&gt;&lt;/a&gt;&lt;/figure&gt;&lt;/div&gt;&#10;&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;&#10;&lt;p&gt;This is my first time participating in T-SQL Tuesday. The &lt;a href="https://glennsqlperformance.com/2022/09/05/t-sql-tuesday-154-invitation-sql-server-2022/"&gt;Invitation&lt;/a&gt; from &lt;a href="https://glennsqlperformance.com/"&gt;Glenn Berry&lt;/a&gt; asks to write about what you&amp;rsquo;ve been doing with SQL 2022.&lt;/p&gt;&#10;&lt;h2 id="getting-dba-dash-ready-for-sql-2022"&gt;Getting &lt;a href="https://github.com/trimble-oss/dba-dash"&gt;DBA Dash&lt;/a&gt; ready for SQL 2022&lt;/h2&gt;&#10;&lt;p&gt;I was eager to test DBA Dash with SQL 2022 and started testing with the first public release (CTP 2.0). I added a SQL 2022 instance to my lab environment, created using &lt;a href="https://automatedlab.org/en/latest/"&gt;AutomatedLab&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Unlike my other lab machines, I ran through the installer for 2022 manually to get up and running quickly and test the new installer.&lt;/p&gt;&#10;&lt;p&gt;DBA Dash only needed some minor modifications to work with SQL 2022. The first and most important step was to &lt;a href="https://github.com/trimble-oss/dba-dash/commit/2cbe38a263808e3882c91bbac01250f8b1163e73"&gt;add version 16 to the hardcoded list of supported versions&lt;/a&gt; and also update some static data for SQL Server 2022. I hardcode the list of supported versions to give me the opportunity to test new versions first and fix any issues.&lt;/p&gt;&#10;&lt;p&gt;This initial support for SQL 2022 was added in May. I&amp;rsquo;ve been running DBA Dash in my lab environment since then and it works well.&lt;/p&gt;&#10;&lt;h2 id="dba-dash---support-for-new-features-in-sql-2022"&gt;DBA Dash - support for new features in SQL 2022&lt;/h2&gt;&#10;&lt;h3 id="qat_deflate-backup-compression"&gt;QAT_DEFLATE Backup Compression&lt;/h3&gt;&#10;&lt;p&gt;&lt;a href="https://wisedataman.com/dba-dash-whats-new-in-2-22-0"&gt;Version 2.22.0&lt;/a&gt; adds support for capturing the compression algorithm used on SQL 2022.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/DBADashBackupCompression-1024x369.png" alt="" class="wp-image-656" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;Glenn Berry has some good articles on this new backup compression algorithm &lt;a href="https://glennsqlperformance.com/2022/08/25/how-to-enable-intel-qat-backup-compression-in-sql-server-2022/"&gt;here&lt;/a&gt; and &lt;a href="https://glennsqlperformance.com/2022/08/28/some-intel-qat-backup-compression-results/"&gt;here&lt;/a&gt;. I&amp;rsquo;m getting similar results to Glenn with my own testing using QAT_DEFLATE (software mode) - &lt;strong&gt;faster backups&lt;/strong&gt;, higher compression and lower resource utilization.&lt;/p&gt;&#10;&lt;h3 id="sysdatabases"&gt;sys.databases&lt;/h3&gt;&#10;&lt;p&gt;SQL 2022 adds some new columns to sys.databases:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;is_data_retention_on&lt;/li&gt;&#10;&lt;li&gt;is_ledger_on&lt;/li&gt;&#10;&lt;li&gt;is_change_feed_enabled&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;I&amp;rsquo;m &lt;a href="https://github.com/trimble-oss/dba-dash/issues/217"&gt;planning&lt;/a&gt; to add these to the DBA Dash collection. Only &lt;strong&gt;is_ledger_on&lt;/strong&gt; is currently &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-ver16"&gt;documented&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 id="other"&gt;Other&lt;/h3&gt;&#10;&lt;p&gt;On the to-do list is to test DBA Dash with contained availability groups. DBA Dash has monitoring for agent jobs and availability groups so it&amp;rsquo;s likely some changes will be required in this area.&lt;/p&gt;&#10;&lt;h2 id="what-im-excited-about-in-sql-2022"&gt;What I&amp;rsquo;m excited about in SQL 2022&lt;/h2&gt;&#10;&lt;p&gt;The &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/performance/intelligent-query-processing?view=sql-server-ver16"&gt;intelligent query processing features&lt;/a&gt; in SQL 2022 and &lt;a href="https://cloudblogs.microsoft.com/sqlserver/2022/07/21/improve-scalability-with-system-page-latch-concurrency-enhancements-in-sql-server-2022/"&gt;tempdb concurrency enhancements&lt;/a&gt; are very interesting. There is also some really useful language enhancements like GENERATE_SERIES, DATE_BUCKET, GREATEST and LEAST that I can see myself using. Null handling also gets easier with IS [NOT] DISTINCT FROM. I can&amp;rsquo;t use any of this for DBA Dash as I want to keep the repository compatible with SQL 2016 for now. The language enhancements will be useful for some of the SaaS databases I manage though once we upgrade.&lt;/p&gt;&#10;&lt;p&gt;The ability to failover back and forth between Azure managed instance and SQL 2022 is also a game changer. It certainly takes some of the risk out of the process if you are considering using managed instances.&lt;/p&gt;&#10;&lt;p&gt;The feature I&amp;rsquo;m most excited about? &lt;a href="https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/sql-server-backup-and-restore-with-s3-compatible-object-storage?view=sql-server-ver16"&gt;Backup/Restore to S3&lt;/a&gt;. If you host SQL instances on AWS you have to figure out how to get your backups to S3. There isn&amp;rsquo;t a standard way to do this. Many people backup to an EBS volume first then push the files to S3 which isn&amp;rsquo;t ideal. EBS storage is expensive and the two step process to get the backups to S3 adds time and complexity to the process. The restore process is also slower and more complex as you need to pull the backups from S3 first before you can restore them.&lt;/p&gt;&#10;&lt;p&gt;The ability to backup directly to S3 is a huge win. It also has value outside of AWS as there are a number of other S3 compatible storage providers.&lt;/p&gt;&#10;</description></item><item><title>September Free Community Tools Awareness Month</title><link>https://wisedataman.com/september-free-community-tools-awareness-month/</link><pubDate>Thu, 08 Sep 2022 21:05:28 +0000</pubDate><guid>https://wisedataman.com/september-free-community-tools-awareness-month/</guid><description>&lt;p&gt;I&amp;rsquo;m writing this post to join in with &lt;a href="https://www.brentozar.com/archive/2022/08/lets-make-september-our-free-community-tools-awareness-month/"&gt;September Free Community Tools Awareness Month&lt;/a&gt;. There are &lt;a href="https://github.com/ktaranov/sqlserver-kit"&gt;many&lt;/a&gt; awesome free community tools. I&amp;rsquo;ve chosen to blog about 3 of them that I think are interesting any maybe less well known in the database community. &lt;em&gt;I&amp;rsquo;m also taking the opportunity to shamelessly plug my own tool, DBA Dash.&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="dba-dash"&gt;&lt;a href="https://github.com/trimble-oss/dba-dash"&gt;DBA Dash&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;DBA Dash is a monitoring tool for SQL Server. It&amp;rsquo;s something I use every day and it provides value in several different ways. It supports everything from SQL 2005 to SQL 2022 and Azure DB.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full is-style-default"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/01/DBADash_Performance_small.png" alt="" class="wp-image-541" loading="lazy"&gt;&lt;/figure&gt;&#10;&lt;p&gt;🏎️If you have a performance issue, DBA Dash can help you get to the root cause. You can troubleshoot an issue that is occurring right now or do a postmortem for an issue that occurred weeks ago.&lt;/p&gt;&#10;&lt;p&gt;🏥It&amp;rsquo;s also a tool for health checks. Do you have missing backups, agent job failures, or corruption? Is log shipping, availability groups, or mirroring broken? Are your servers running out of disk space? DBA Dash checks all of these and more. Recently added is a &lt;a href="https://wisedataman.com/dba-dash-whats-new-in-2-22-0"&gt;check for identity columns&lt;/a&gt; running out of values.&lt;/p&gt;&#10;&lt;p&gt;⚙️DBA Dash captures configuration data for your whole SQL Server estate (config settings, trace flags, tempdb). Use the configuration data to check for configuration settings that are different between your SQL instances - great for validating the config of new SQL instances. Check the patch level of your SQL instances. Keep track of when updates were installed and configuration changes made.&lt;/p&gt;&#10;&lt;p&gt;l created this tool and I&amp;rsquo;m also it&amp;rsquo;s #1 user. The tool is totally free without restrictions or limitations - even better it&amp;rsquo;s open source. &lt;strong&gt;&lt;a href="https://github.com/trimble-oss/dba-dash"&gt;Get it on GitHub&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;This video will give you a quick overview of the tool.&lt;/p&gt;&#10;&lt;figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"&gt;&lt;div class="wp-block-embed__wrapper"&gt;https://www.youtube.com/watch?v=X7e4zElOQ3c&lt;/div&gt;&lt;/figure&gt;&#10;&lt;p&gt;_Note: Th_is &lt;em&gt;video was created in January when the tool first launched. Many new features and enhancements have been made since the video was created.&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="automatedlab"&gt;&lt;a href="https://automatedlab.org/en/latest/"&gt;AutomatedLab&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;AutomatedLab enables you to quickly set up lab environments on Hyper-V and Azure. I use this to create lab environments for DBA Dash on Hyper-V.&lt;/p&gt;&#10;&lt;p&gt;The lab environments enable me to test DBA Dash with SQL versions from 2005 to 2022 as well as availability groups, and different configurations. I also use the lab environment as a general playground for learning and experimentation - something useful to have for any DBA.&lt;/p&gt;&#10;&lt;p&gt;The power of AutomatedLab is that I can re-create my lab by running a PowerShell script and I can tear it down just as easily. Infrastructure as code!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://dbatools.io/"&gt;dbatools&lt;/a&gt; is also a key component to setting up my lab environment and it&amp;rsquo;s one of my favourite community tools. Use this for automating anything relating to SQL Server.&lt;/p&gt;&#10;&lt;h2 id="pssdiagsqlnexus"&gt;&lt;a href="https://github.com/microsoft/SqlNexus"&gt;Pssdiag/SqlNexus&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;This is a monitoring tool for SQL Server, but unlike DBA Dash it&amp;rsquo;s not a tool for 24/7 monitoring. I don&amp;rsquo;t use this tool very often but it can be useful if you are dealing with a particularly tricky SQL issue.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;ve been a DBA for 17 years and I&amp;rsquo;ve had a small number of edge case issues that required a phone call to Microsoft product support. During these engagements I&amp;rsquo;ve been asked to run a pssdiag session and upload it for their offline analysis. You can create &lt;strong&gt;your own&lt;/strong&gt; pssdiag session with SqlDiag Manager and analyse it with SqlNexus.&lt;/p&gt;&#10;&lt;p&gt;I would run this tool for short periods of time while you are experiencing particularly tricky issues and use other tools like DBA Dash for your regular monitoring.&lt;/p&gt;&#10;&lt;p&gt;This is a Microsoft tool, but like the other tools on the list it&amp;rsquo;s also open source!&lt;/p&gt;&#10;</description></item><item><title>DBA Dash – What’s new in 2.22.0? 🎉</title><link>https://wisedataman.com/dba-dash-whats-new-in-2-22-0/</link><pubDate>Thu, 08 Sep 2022 10:34:52 +0000</pubDate><guid>https://wisedataman.com/dba-dash-whats-new-in-2-22-0/</guid><description>&lt;h2 id="identity-columns-collection"&gt;Identity Columns collection&lt;/h2&gt;&#10;&lt;p&gt;If your table runs out of identity values, you might see an error message similar to the one below:&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;Msg 8115, Level 16, State 1, Line 7&lt;br&gt;&#10;Arithmetic overflow error converting IDENTITY to data type int.&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;DBA Dash now has monitoring for identity values. You can see when you are about to run out of identity values which allows you time to plan and fix these problems &lt;strong&gt;before&lt;/strong&gt; they cause errors in your database.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/IdentityColumnsSummary-1024x200.png" alt="" class="wp-image-654" loading="lazy"&gt;&lt;figcaption&gt;Identity Columns on DBA Dash Summary page&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/IdentityColumns-1024x106.png" alt="" class="wp-image-655" loading="lazy"&gt;&lt;figcaption&gt;Identity Columns drilldown&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p&gt;&lt;a href="https://github.com/trimble-oss/dba-dash/blob/main/Docs/IdentityColumns.md"&gt;More information here.&lt;/a&gt;&lt;/p&gt;&#10;&lt;h2 id="backup-compression-algorithms-for-sql-2022"&gt;Backup Compression Algorithms for SQL 2022&lt;/h2&gt;&#10;&lt;p&gt;SQL 2022 has the option to use Intel QAT backup compression. In software mode this is supported on standard and enterprise editions. It&amp;rsquo;s significantly faster, produces higher levels of compression and uses less resources. Hardware mode is just supported on enterprise edition and can significantly offload the CPU cost of compressing your backups.&lt;/p&gt;&#10;&lt;p&gt;Glenn Berry has some good articles on this &lt;a href="https://glennsqlperformance.com/2022/08/25/how-to-enable-intel-qat-backup-compression-in-sql-server-2022/"&gt;here&lt;/a&gt; and &lt;a href="https://glennsqlperformance.com/2022/08/28/some-intel-qat-backup-compression-results/"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;So what&amp;rsquo;s this got to do with DBA Dash? &lt;strong&gt;DBA Dash now captures the compression algorithm used from msdb.dbo.backupset for your latest backups&lt;/strong&gt;. You can now where QAT_DEFLATE compression is in use.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/DBADashBackupCompression-1024x369.png" alt="" class="wp-image-656" loading="lazy"&gt;&lt;figcaption&gt;New columns added to capture compression algorithm used for last backup&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p&gt;DBA Dash also tracks sys.configurations settings in use across all your SQL instances, including the new configuration options used to enable QAT_DEFLATE compression. You can see the configuration setting in use and also track when settings have been changed.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/09/DBADashConfigurationBackupCompression-1024x348.png" alt="" class="wp-image-657" loading="lazy"&gt;&lt;figcaption&gt;'#Tracking changes to sys.configurations&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h2 id="download"&gt;Download&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="https://github.com/trimble-oss/dba-dash/releases"&gt;Download Now&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>DBA Dash - What's new in 2.21.0? 🚀</title><link>https://wisedataman.com/dba-dash-whats-new-in-2-21-0/</link><pubDate>Tue, 09 Aug 2022 21:16:25 +0000</pubDate><guid>https://wisedataman.com/dba-dash-whats-new-in-2-21-0/</guid><description>&lt;h2 id="intro"&gt;Intro&lt;/h2&gt;&#10;&lt;p&gt;The first public release of DBA Dash was in January 2022 and version 2.21.0 is the 24th release.🎉 A lot has changed with many new features added as well as bug fixes. I haven&amp;rsquo;t really blogged much about the changes, but I thought it might be good to capture what its new for significant releases. So here is what is new and cool in 2.21.0!&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;You can see the full change log &lt;a href="https://github.com/trimble-oss/dba-dash/releases"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="metrics-tab"&gt;Metrics tab&lt;/h2&gt;&#10;&lt;p&gt;The metrics tab was previously a wall of numbers - the Max, Min, Avg, Total &amp;amp; Current value of all the collected performance counters. At the click of a button you could see a chart for any counter over time for the selected period. It was limited to showing 1 chart at a time.&lt;/p&gt;&#10;&lt;p&gt;In 2.17.0 it was possible to configure threshold values for your counters - improving on the wall of numbers by highlighting counters that need your attention.&lt;/p&gt;&#10;&lt;p&gt;Now in 2.21.0 when you click &lt;strong&gt;view&lt;/strong&gt; to view a chart for a particular counter, it adds a new chart. You can view charts for multiple counters simultaneously. Also, you can add other charts that are not os performance counters - CPU, Blocking, IO, Object Execution and Waits. This provides additional context for your performance counters. You can re-order the charts and remove them at the click of a button.&lt;/p&gt;&#10;&lt;p&gt;Once you&amp;rsquo;ve created a useful dashboard you can save and re-load it at the click of a button. You can save the view for yourself or share it with your team.&lt;/p&gt;&#10;&lt;p&gt;See it in action &lt;a href="https://wisedataman.com/wp-content/uploads/2022/08/DBADash2.21.0.gif"&gt;here:&lt;/a&gt;&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;a href="https://wisedataman.com/wp-content/uploads/2022/08/DBADash2.21.0.gif"&gt;&lt;img src="https://wisedataman.com/wp-content/uploads/2022/08/DBADash2.21.0.gif" alt="DBA Dash Metrics tab" class="wp-image-647" title="DBA Dash Metrics" loading="lazy"&gt;&lt;/a&gt;&lt;figcaption&gt;DBA Dash - Metrics tab&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You can easily configure which performance counters are collected. Also, you can collect any metric you like that can be queried with T-SQL. See &lt;a href="https://github.com/trimble-oss/dba-dash/blob/main/Docs/OSPerformanceCounters.md"&gt;here&lt;/a&gt; for details on how to customize the collection.&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="performance-summary-tab"&gt;Performance Summary tab&lt;/h2&gt;&#10;&lt;p&gt;The performance summary tab now has saved views the same as the metrics tab. You could save the layout previously but it wasn&amp;rsquo;t possible to save multiple versions or to share those with the rest of the team.&lt;/p&gt;&#10;</description></item></channel></rss>