{"id":73,"date":"2012-11-10T17:07:55","date_gmt":"2012-11-10T23:07:55","guid":{"rendered":"http:\/\/s1095387061.online-home.ca\/?p=73"},"modified":"2015-02-13T20:50:14","modified_gmt":"2015-02-14T03:50:14","slug":"msdb-database-cleanup","status":"publish","type":"post","link":"https:\/\/databaserefresh.com\/blog\/msdb-database-cleanup\/","title":{"rendered":"MSDB database cleanup"},"content":{"rendered":"<p>Disk space these days is not as expensive as it used to be, but as a DBA I like to keep things tidy and optimize as much things as possible. Cleaning up databases and old backups, archiving databases are some of my regular tasks.<\/p>\n<p>There will be a couple examples on MSDB database cleanup in this post with screenshots and reports.<\/p>\n<p>MSDB database contains a lot of historical records related to the email, backups and maintenance plans. It does not usually grow too fast, but it may have a lot of historical information in large environments. If you do not maintain the history properly msdb sometimes can have years of history.<\/p>\n<p>Keep in mind that some of the historical information is required for databases restores, for audit, etc. So, before you start cleaning up your database make sure that this does not go against your policies. Some DBAs base their restore scripts on the msdb database&#8217;s tables, this also has to be taken into consideration.<\/p>\n<p>Some settings for the job history could be found under SQL Server Agent. Ideally you would setup \u201cHistory Cleanup Task\u201d using Maintenance Plans in SQL Server Management Studio (SSMS). This is quick and easy way:<\/p>\n<p> <a href=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img1.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-79\" title=\"bp3_img1\" src=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img1.gif\" alt=\"\" width=\"436\" height=\"292\" \/><\/a><\/p>\n<p>But there are circumstances when you may need to do this manually, for example: SQL Server Agent is disabled on SQL Server; you inherited old SQL Server where history has not been cleaned up since server setup. Also, keep in mind that \u201cHistory Cleanup Task\u201d does not include Database Mail logs.<\/p>\n<p>&nbsp;<\/p>\n<h2><strong>Manual Cleanup<\/strong><\/h2>\n<p>Audit requirements in this example will be to keep 6 months of historical data and 6 months of backup history (based on Service Level Agreements). This is not real life scenario that we will be only using it to demonstrate database size changes after the cleanup.<\/p>\n<p>I would like to keep email sending log for the last 6 months as well as evidence for auditors that I get e-mails about critical system errors.<\/p>\n<p>Here is the msdb database size on SQL Server with 50 databases and 1 year of history:<\/p>\n<p> <a href=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img2.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-80\" title=\"bp3_img2\" src=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img2.gif\" alt=\"\" width=\"618\" height=\"342\" \/><\/a> <\/p>\n<p> Let\u2019s run SSMS report showing Disk Usage by Top Tables:<\/p>\n<p>  <a href=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img3.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-81\" title=\"bp3_img3\" src=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img3.gif\" alt=\"\" width=\"620\" height=\"186\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><strong><span style=\"text-decoration: underline;\">Step 1: Backup-restore history cleanup<\/span><\/strong><\/p>\n<p>This is done by executing <strong><em>sp_delete_backuphistory<\/em><\/strong> stored procedure. Here are the tables affected (as per BOL):<\/p>\n<p><em>\u201c\u2026 <strong>sp_delete_backuphistory<\/strong> must be run from the <strong>msdb<\/strong> database and affects the following tables:<\/em><\/p>\n<ul>\n<li><em>backupfile <\/em><\/li>\n<li><em>backupfilegroup <\/em><\/li>\n<li><em>backupmediafamily <\/em><\/li>\n<li><em>backupmediaset <\/em><\/li>\n<li><em>backupset <\/em><\/li>\n<li><em>restorefile <\/em><\/li>\n<li><em>restorefilegroup <\/em><\/li>\n<li><em>restorehistory <\/em><\/li>\n<\/ul>\n<p><em>The physical backup files are preserved, even if all the history is deleted.\u201d<\/em><\/p>\n<p>&nbsp;<\/p>\n<p>The stored procedure\u2019s parameters: <\/p>\n<p><strong>sp_delete_backuphistory [ @oldest_date =<\/strong> ] &#8216;oldest_date&#8217;<\/p>\n<p>&nbsp;<\/p>\n<p>The script to cleanup backup-restore history for our example scenario:<\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #800000;\">sp_delete_backuphistory <\/span> @oldest_date = <span style=\"color: #ff0000;\">&#8216;January 1, 2012&#8217;<\/span><\/em><\/p>\n<p>&nbsp;<\/p>\n<p><strong><span style=\"text-decoration: underline;\">Step 2: Mail history cleanup<\/span><\/strong><\/p>\n<p>This is done by executing <em>sysmail_delete_log_sp<\/em> and <em>sysmail_delete_mailitems_sp <\/em>stored procedures.<\/p>\n<p>&nbsp;<\/p>\n<p>The <strong><em>sysmail_delete_log_sp<\/em><\/strong> stored procedure deletes entries from the Database Mail log (msdb.dbo.sysmail_log table).<\/p>\n<p>&nbsp;<\/p>\n<p>The stored procedure\u2019s parameters: <\/p>\n<p><strong>sysmail_delete_log_sp  [ [ @logged_before = ] <\/strong>&#8216;logged_before&#8217;<strong> ]<\/strong><\/p>\n<p><strong>    [, [ @event_type = ] <\/strong>&#8216;event_type&#8217;<strong> ]<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>The script to cleanup old mail log records for our example:<\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sysmail_delete_log_sp<\/span>    @logged_before = <span style=\"color: #ff0000;\">&#8216;January 1, 2012&#8217;<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\">\n<p>The <strong><em>sysmail_delete_mailitems_sp<\/em><\/strong> stored procedure deletes e-mail messages from the Database Mail internal tables (msdb.dbo.sysmail_allitems table).<\/p>\n<p>&nbsp;<\/p>\n<p>The stored procedure\u2019s parameters: <\/p>\n<p><strong>sysmail_delete_mailitems_sp  [ [ @sent_before = ] <\/strong>&#8216;sent_before&#8217;<strong> ]<\/strong><\/p>\n<p><strong>    [ , [ @sent_status = ] <\/strong>&#8216;sent_status&#8217;<strong> ]<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>The script to cleanup old mail items for our example scenario:<\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sysmail_delete_mailitems_sp  <\/span> @sent_before = <span style=\"color: #ff0000;\"> &#8216;January 1, 2012&#8217;<\/span> , @sent_status =  NULL<span style=\"color: #339966;\"> &#8212; all statuses<\/span><\/em><\/p>\n<p>&nbsp;<\/p>\n<p><strong><span style=\"text-decoration: underline;\">Step 3: Maintenance plans log cleanup<\/span><\/strong><\/p>\n<p>This is done by executing <em>sp_maintplan_delete_log<\/em> stored procedure.<\/p>\n<p>The <strong><em>sp_maintplan_delete_log<\/em><\/strong> stored procedure permanently deletes entries and details from the Maintenance Plans log (msdb.dbo.sysmaintplan_logdetail  and msdb.dbo.sysmaintplan_log  tables).<\/p>\n<p>The stored procedure\u2019s parameters: <\/p>\n<p><strong>sp_maintplan_delete_log [ [@plan_id = ] <\/strong>&#8216;plan_id&#8217;<strong> ]<\/strong><\/p>\n<p><strong>    [, [@subplan_id = ] <\/strong>&#8216;subplan_id&#8217;<strong> ] <\/strong><\/p>\n<p><strong>    [, [@oldest_time = ] <\/strong>&#8216;oldest_time&#8217;<strong> ]<\/strong><\/p>\n<p><strong> <\/strong> <\/p>\n<p>The script to cleanup old maintenance plans log records for our example scenario:<\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sp_maintplan_delete_log   <\/span> @oldest_time  = <span style=\"color: #ff0000;\">&#8216;January 1, 2012&#8217;<\/span><\/em><\/p>\n<p>&nbsp;<\/p>\n<p><strong><span style=\"text-decoration: underline;\">Step 4: Job history cleanup<\/span><\/strong><\/p>\n<p>This is done by executing <em>sp_purge_jobhistory<\/em> stored procedure.<\/p>\n<p>The <strong><em>sp_purge_jobhistory<\/em><\/strong> stored procedure permanently deletes entries and details from the job history (msdb.dbo.sysjobhistory  table).<\/p>\n<p>The stored procedure\u2019s parameters:<\/p>\n<p><strong>sp_maintplan_delete_log [ [@plan_id = ] <\/strong>&#8216;plan_id&#8217;<strong> ]<\/strong><\/p>\n<p><strong>    [, [@subplan_id = ] <\/strong>&#8216;subplan_id&#8217;<strong> ] <\/strong><\/p>\n<p><strong>    [, [@oldest_time = ]<\/strong> &#8216;oldest_time&#8217;<strong> ]<\/strong><\/p>\n<p><strong> <\/strong> <\/p>\n<p>The script to cleanup old maintenance plans log records for our example scenario:<\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sp_maintplan_delete_log<\/span>    @oldest_time  = <span style=\"color: #ff0000;\">&#8216;January 1, 2012&#8217;<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\">\n<h2>All steps in one script <\/h2>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">DECLARE<\/span> @date <span style=\"color: #0000ff;\">DATE<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">SET<\/span> @date = <span style=\"color: #ff0000;\">&#8216;January 1, 2012&#8217;<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em> <\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sp_delete_backuphistory <\/span> @oldest_date = @date<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sysmail_delete_log_sp   <\/span> @logged_before = @date<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sysmail_delete_mailitems_sp  <\/span> @sent_before =  @date , @sent_status =  <span style=\"color: #808080;\">NULL<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sp_maintplan_delete_log   <\/span> @oldest_time  = @date<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">EXEC<\/span> msdb.dbo.<span style=\"color: #993300;\">sp_purge_jobhistory      <\/span> @oldest_date = @date<\/em><\/p>\n<p>&nbsp;<\/p>\n<p> Now if we run the same database reports from SSMS as before we will see the difference:<\/p>\n<p> <a href=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img4.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-82\" title=\"bp3_img4\" src=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img4.gif\" alt=\"\" width=\"619\" height=\"192\" \/><\/a><\/p>\n<p> <a href=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img5.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-78\" title=\"bp3_img5\" src=\"http:\/\/databaserefresh.com\/wp-content\/uploads\/2015\/02\/bp3_img5.gif\" alt=\"\" width=\"617\" height=\"349\" \/><\/a><\/p>\n<p> The database\u2019s size reduced by almost 64%!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disk space these days is not as expensive as it used to be, but as a DBA I like to keep things tidy and optimize as much things as possible. Cleaning up databases and old backups, archiving databases are some &hellip; <a href=\"https:\/\/databaserefresh.com\/blog\/msdb-database-cleanup\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[7,3],"tags":[23,22],"class_list":["post-73","post","type-post","status-publish","format-standard","hentry","category-sql_maint","category-sql_server","tag-backup-history","tag-msdb"],"_links":{"self":[{"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/posts\/73","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/comments?post=73"}],"version-history":[{"count":32,"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/posts\/73\/revisions"}],"predecessor-version":[{"id":285,"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/posts\/73\/revisions\/285"}],"wp:attachment":[{"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/media?parent=73"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/categories?post=73"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/databaserefresh.com\/blog\/wp-json\/wp\/v2\/tags?post=73"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}