WSUS Delete Obsolete Updates

Posted: August 15, 2017 in Configuration Manager, Information, SQL, Windows Update
Tags: , , ,

NOTE: Usual warnings apply. Do a backup before making any changes. If you are unsure about anything in the post then ask or look for more information or help before attempting it.

Over time WSUS will accumulate update metadata that can create performance issues for clients. In large environments this can be quite an issue.

There is a script Microsoft often provides during Premier Support calls to cleanup this update metadata, however there are a few issues:

  • The query can take a *really* long time to run if there are a lot of updates to cleanup. In some cases it can take *days*
  • You need to stop all the WSUS services while it runs
  • If it fails for whatever reason, it will have to start all over because it doesn’t commit the changes until it completes successfully
  • While it runs, the TEMPDB and Transaction logs will grow quite significantly until the data is committed
  • It gives no useful information on progress

There is a TechNet article (This is essential reading and has LOTS of important stuff) and a Forum Post where an improved version was written that gave progress of the cleanup, however it didn’t address the temp/transaction growth issues or the time issues. To this end I have applied my very rudimentary SQL scripting skills.

To find out just how many updates are waiting to be cleaned up, run this stored procedure:

EXEC spGetObsoleteUpdatesToCleanup

Firstly, when the script runs on a default WSUS install it can take over a minute to process *each* record. If there are thousands or tens of thousands or updates to remove this is going to take a while. There is an index you can add to the WSUS table that dramatically improves this so it happens at about 1 second per record. Microsoft confirmed this index is OK, however it is not officially supported (at time of writing)

USE [SUSDB]
GO
CREATE NONCLUSTERED INDEX [IX_tbRevisionSupersedesUpdate] ON [dbo].[tbRevisionSupersedesUpdate]([SupersededUpdateID])
GO
CREATE NONCLUSTERED INDEX [IX_tbLocalizedPropertyForRevision] ON [dbo].[tbLocalizedPropertyForRevision]([LocalizedPropertyID])
GO

Now to the cleanup script. Simply this script will cleanup obsolete records, provide progress feedback and also allow you to run it in small blocks. This allows you to run in short blocks without needing to stop the WSUS server and avoids generating huge transaction loads on the SQL server.

To “tweak” the script, modify this line with the number of updates you want to do in each block. Start with 50, see how it runs in your environment and increase as needed. Ideally don’t run batches that take more than 5-10 minutes to prevent those SQL transaction logs growing.

IF @curitem < 101

If you do want to run a larger batch that may take hours, you should of course stop the WSUS services to do so. Also, don’t run this script if a WSUS Sync is in progress or scheduled to start.

USE SUSDB
DECLARE @var1 INT, @curitem INT, @totaltodelete INT
DECLARE @msg nvarchar(200)
CREATE TABLE #results (Col1 INT) INSERT INTO #results(Col1)
EXEC spGetObsoleteUpdatesToCleanup
SET @totaltodelete = (SELECT COUNT(*) FROM #results)
SELECT @curitem=1
DECLARE WC Cursor FOR SELECT Col1 FROM #results
OPEN WC
FETCH NEXT FROM WC INTO @var1 WHILE (@@FETCH_STATUS > -1)
BEGIN SET @msg = cast(@curitem as varchar(5)) + '/' + cast(@totaltodelete as varchar(5)) + ': Deleting ' + CONVERT(varchar(10), @var1) + ' ' + cast(getdate() as varchar(30))
RAISERROR(@msg,0,1) WITH NOWAIT
EXEC spDeleteUpdate @localUpdateID=@var1
SET @curitem = @curitem +1
IF @curitem < 101
 FETCH NEXT FROM WC INTO @var1
END
CLOSE WC
DEALLOCATE WC
DROP TABLE #results

deleteobsolete

If for any reason the script is interrupted, you will find SQL still has the transaction table open and won’t let you run again (There is already an object named ‘#results’ in the table). To resolve this highlight and execute the last line to drop the table.

If this still doesn’t help, close the SQL Studio Manager session and you should be prompted with a warning about uncommitted transactions. Select Yes to commit then reopen and start the query again.

If for any reason the query is not properly closed there may be locks held on the SQL database that will prevent the normal WSUS service functioning resulting in failure of service.

 

Advertisements
Comments
  1. Tom Dub says:

    You can alos run this (as suggested by MS) on the WSUS server

    [reflection.assembly]::LoadWithPartialName(“Microsoft.UpdateServices.Administration”) | out-null
    $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
    $cleanupScope = new-object Microsoft.UpdateServices.Administration.CleanupScope;
    $cleanupScope.DeclineSupersededUpdates = $true
    $cleanupScope.DeclineExpiredUpdates = $true
    $cleanupScope.CleanupObsoleteUpdates = $true
    $cleanupScope.CompressUpdates = $true
    #$cleanupScope.CleanupObsoleteComputers = $true
    $cleanupScope.CleanupUnneededContentFiles = $true
    $cleanupManager = $wsus.GetCleanupManager();
    $cleanupManager.PerformCleanup($cleanupScope);

    • Scott says:

      Yes, that will trigger the normal WSUS clean up actions, but it will timeout/crash if there are a large number of obsolete updates to be cleaned. As I also mentioned the SQL server transaction and tempdb files will keep growing while that clean up runs and can cause significant resource issues.
      The reason I gave this example is to allow you to do the clean up in smaller batches that doesn’t overwhelm the SQL server itself.

  2. Jeff says:

    i cannot get it to run any faster than 2 minutes a deletion. i have ran the;

    USE [SUSDB]
    GO
    CREATE NONCLUSTERED INDEX [IX_tbRevisionSupersedesUpdate] ON [dbo].[tbRevisionSupersedesUpdate]([SupersededUpdateID])
    GO
    CREATE NONCLUSTERED INDEX [IX_tbLocalizedPropertyForRevision] ON [dbo].[tbLocalizedPropertyForRevision]([LocalizedPropertyID])
    GO

    and it completes sucesfully, but still only deleting 1 every 2 minutes.

    1/49101: Deleting 1645689 Apr 24 2018 3:37PM
    2/49101: Deleting 1645650 Apr 24 2018 3:38PM
    3/49101: Deleting 1645615 Apr 24 2018 3:40PM
    4/49101: Deleting 1645580 Apr 24 2018 3:42PM
    5/49101: Deleting 1645545 Apr 24 2018 3:44PM

    • Scott says:

      You have a *lot* of updates for it to work through. Unless you can add more memory or CPU to that SQL server it will probably take a while to work through that many deletes. I’d suggest doing batches of 1000 at a time outside business hours until you get them all clear. As the number to delete gets smaller you should see the speed improve.
      Remember, don’t run it while a DB sync is going to run, and watch the memory/CPU utilisation on the SQL server to make sure it isn’t impacting your normal client activity.

      • Jeff says:

        Will do. Thank you very much.

        I have been running small batches and the last couple have had a few 1 minute deletions.

        • Scott says:

          Excellent. Keep it up, take it easy and don’t rush it. Once you have it under control it will be much easier to keep it sorted out.

  3. […] Wsus Delete Obsolete Updates – where the key is the addition of the added indexes to SUSDB. […]

  4. Rienus says:

    Perfect, works fine for me! Thanks 😉

  5. Chris says:

    This page saved me so much pain.
    Everything worked a treat, I now have a working WSUS DB again.

    What I would add is, If like me you hit this issue because the Database exceeded the 10GB license limit, you would need to Shrink the database after.

    Also,
    maybe add pdateing statistics via
    EXEC sp_updatestats

    Thanks again,
    Chris

    • Scott says:

      What is the 10GB license limit? Is this from the Windows Internal Database? I’ve never run a WSUS server using it so I haven’t encountered that before.

  6. boss01 says:

    Nice explanation!,

    The SQL Query provided in the below link is taking a lot of time to execute, moreover, there are no instructions to stop any services before running the query!!

    did anyone ran this query for WID (susdb)?
    my db is 40 gb
    is it ok to stop the query once its fired?

    https://blogs.technet.microsoft.com/configurationmgr/2016/01/26/the-complete-guide-to-microsoft-wsus-and-configuration-manager-sup-maintenance/

    • Scott says:

      It is OK to stop the query, however the transaction will all be rolled back (which itself can take a long time) and you’ll have to start over. That’s why I use the script that lets you do it in small blocks. Start with 10 and see how long it takes, then do 100. From that you will be able to work out what times work best.
      When I started a big cleanup I wouldn’t do any more than 30 minutes worth at a time. The SQL server has to do a lot of work and cleanup to process this and it could take weeks to clean it all up if it hasn’t been done before. Once sorted out things will go *much* faster for future cleanups.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s