Рейтинг:1

Решено: исправлен сбой очистки сервера WSUS при удалении ненужных обновлений.

флаг jp

WSUS всегда был проклятием для каждого ИТ-администратора. Сколько потоков вы найдете с одной и той же проблемой - сбой мастера очистки сервера. Текст ниже работал для меня.

Я пробовал множество SQL-скриптов как от Microsoft, так и из общедоступных источников, и все они давали неоднозначные результаты. На прошлой неделе наш сервер WSUS снова начал кашлять меховыми комками, поэтому я заплатил деньги и создал тикет в службу поддержки. Приведенный ниже текст в точности соответствует полученному от службы поддержки MS. Шаг 8, в моем случае, занял полтора дня, и даже с некоторыми ошибками. Я проигнорировал эти ошибки. Шаг 9 был быстрым, но и с парой ошибок. Я также проигнорировал эти ошибки (ошибки взаимоблокировки). После завершения я повторно запустил мастер очистки сервера, и он работал отлично. Все они были запущены в среде SQL Server Management Studio и с использованием WID.

Это не вопрос, а моя цель — попытаться помочь другим администраторам решить эти хронические проблемы с WSUS. Ваш пробег может быть очень большим - я надеюсь, что это поможет некоторым из вас.

Пожалуйста, следуйте указанным ниже шагам:

--------------------------------------------- --------------------------------------------- ----------------------------------------

1) Переиндексация:

ИСПОЛЬЗОВАТЬ ЮСДБ; 
ИДТИ 
УСТАНОВИТЬ БЕЗ СЧЕТА; 
 
-- Перестроить или реорганизовать индексы на основе уровней их фрагментации. 
ЗАЯВИТЕ ТАБЛИЦУ @work_to_do ( 
    объектный идентификатор 
    , индекс int 
    , плавающая плотность страницы 
    , поплавок фрагментации 
    , числовое значение 
) 
 
ОБЪЯВИТЬ @objectid int; 
ОБЪЯВИТЬ @indexid int; 
DECLARE @schemaname nvarchar(130);  
DECLARE @objectname nvarchar(130);  
DECLARE @indexname nvarchar(130);  
DECLARE @numrows int 
DECLARE @density float; 
DECLARE @fragmentation float; 
ОБЪЯВИТЬ @command nvarchar(4000);  
DECLARE бит @fillfactorset 
DECLARE @numpages int 
 
-- Выберите индексы, которые необходимо дефрагментировать, на основе следующих 
-- * Низкая плотность страницы 
-- * Внешняя фрагментация высока по отношению к размеру индекса 
PRINT 'Оценка фрагментации: Начало. ' + конвертировать (nvarchar, getdate(), 121)  
ВСТАВЬТЕ @work_to_do 
ВЫБРАТЬ 
    f.object_id 
    , index_id 
    , avg_page_space_used_in_percent 
    , avg_fragmentation_in_percent 
    , количество_записей 
ОТ  
    sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'SAMPLED') AS f 
КУДА 
    (f.avg_page_space_used_in_percent < 85,0 и f.avg_page_space_used_in_percent/100,0 * page_count < page_count - 1) 
    или (f.page_count > 50 и f.avg_fragmentation_in_percent > 15,0) 
    или (f.page_count > 10 и f.avg_fragmentation_in_percent > 80,0) 
 
PRINT 'Количество индексов для перестроения: ' + cast(@@ROWCOUNT as nvarchar(20)) 
 
PRINT 'Оценка фрагментации: Конец. ' + конвертировать (nvarchar, getdate(), 121) 
 
ВЫБЕРИТЕ @numpages = сумма (ps.used_page_count) 
ОТ 
    @work_to_do КАК ФАЙ 
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ sys.indexes AS i ON fi.objectid = i.object_id и fi.indexid = i.index_id 
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ sys.dm_db_partition_stats AS ps на i.object_id = ps.object_id и i.index_id = ps.index_id 
 
-- Объявить курсор для списка обрабатываемых индексов. 
ОБЪЯВИТЬ curIndexes CURSOR FOR SELECT * FROM @work_to_do 
 
-- Откройте курсор. 
ОТКРЫТЬ 
 
-- Цикл по индексам 
ПОКА (1=1) 
НАЧИНАТЬ 
    ПОЛУЧИТЬ СЛЕДУЮЩИЙ ОТ curIndexes 
    INTO @objectid, @indexid, @density, @fragmentation, @numrows; 
    ЕСЛИ @@FETCH_STATUS < 0 BREAK; 
 
    ВЫБРАТЬ  
        @objectname = QUOTENAME(o.name) 
        , @schemaname = QUOTENAME(s.name) 
    ОТ  
        sys.objects КАК o 
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ sys.schemas as s ON s.schema_id = o.schema_id 
    КУДА  
        о.object_id = @objectid; 
 
    ВЫБРАТЬ  
        @indexname = QUOTENAME(имя) 
        , @fillfactorset = CASE fill_factor WHEN 0 THEN 0 ELSE 1 END 
    ОТ  
        sys.indexes 
    КУДА 
        object_id = @objectid AND index_id = @indexid; 
 
    ЕСЛИ ((@density МЕЖДУ 75,0 И 85,0) И @fillfactorset = 1) ИЛИ (@фрагментация < 30,0) 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE'; 
    ИНАЧЕ, ЕСЛИ @numrows >= 5000 И @fillfactorset = 0 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' ПЕРЕСТРОЙТЕ С (FILLFACTOR = 90)'; 
    ЕЩЕ 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD'; 
    PRINT convert(nvarchar, getdate(), 121) + N' Выполнение: ' + @command; 
    ВЫПОЛНИТЬ (@команда); 
    PRINT convert(nvarchar, getdate(), 121) + N' Done.'; 
КОНЕЦ 
 
-- Закройте и освободите курсор. 
ЗАКРЫТЬ 
УДАЛИТЬ curIndexes; 
 
 
ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ * ОТ @work_to_do) 
НАЧИНАТЬ 
    PRINT 'Приблизительное количество страниц в фрагментированных индексах: ' + cast(@numpages as nvarchar(20)) 
    ВЫБЕРИТЕ @numpages = @numpages - сумма (ps.used_page_count) 
    ОТ 
        @work_to_do КАК ФАЙ 
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ sys.indexes AS i ON fi.objectid = i.object_id и fi.indexid = i.index_id 
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ sys.dm_db_partition_stats AS ps на i.object_id = ps.object_id и i.index_id = ps.index_id 
 
    PRINT 'Приблизительное количество освобожденных страниц: ' + cast(@numpages as nvarchar(20)) 
КОНЕЦ 
ИДТИ 
 
 
--Обновить всю статистику 
PRINT 'Обновление всей статистики.' + конвертировать (nvarchar, getdate(), 121)  
EXEC sp_updatestats 
PRINT 'Завершено обновление статистики.' + конвертировать (nvarchar, getdate(), 121)  
ИДТИ 

--------------------------------------------- ---------------------------------------------

2) Запустите приведенный ниже запрос, чтобы получить количество замененных обновлений.
 
ВЫБЕРИТЕ ID обновления из vwMinimalUpdate, ГДЕ IsSuperseded = 1 И отклонено = 0

--------------------------------------------- ------------------------------------

3) Запустите приведенный ниже запрос, чтобы удалить все замененные обновления и запустить мастер очистки сервера.
 

DECLARE @var1 уникальный идентификатор 
ОБЪЯВИТЬ @msg nvarchar(100) 
ОБЪЯВИТЬ Курсор DU
ЗА
ВЫБЕРИТЕ ID обновления из vwMinimalUpdate, ГДЕ IsSuperseded = 1 И отклонено = 0
Открыть ДД
ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ DU В @var1
ПОКА (@@FETCH_STATUS > -1) 
НАЧИНАТЬ 
 RAISERROR(@msg,0,1) WITH NOWAIT exec spDeclineUpdate @updateID=@var1,@adminName=N'domain\user',@failIfReplica=1
ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ DU В @var1 
КОНЕЦ 
ЗАКРЫТЬ ДУ 
ОСВОБОДИТЬ DU 

--------------------------------------------- -------------------------------------

4) Запустите следующий SQL-запрос на SQL к базе данных SUSDB, чтобы получить количество обновлений для очистки:
 
exec spGetObsoleteUpdatesToCleanup 

--------------------------------------------- --------------------------------------

5) Запустите приведенный ниже запрос в базе данных SQL, чтобы удалить обновления, а затем запустите мастер очистки сервера:
 
ОБЪЯВИТЬ @var1 INT 
ОБЪЯВИТЬ @msg nvarchar(100) 
 
СОЗДАТЬ ТАБЛИЦУ #results (Col1 INT) 
ВСТАВИТЬ В #results(Col1) EXEC spGetObsoleteUpdatesToCleanup 
 
ОБЪЯВИТЬ WC Курсор 
ЗА 
ВЫБЕРИТЕ Col1 ИЗ #results 
 
ОТКРЫТЫЙ ТУАЛЕТ 
ПОЛУЧИТЬ СЛЕДУЮЩУЮ ИЗ ТУАЛЕТА 
ВНУТРИ @var1 
ПОКА (@@FETCH_STATUS > -1) 
BEGIN SET @msg = 'Удаление' + CONVERT(varchar(10), @var1) 
RAISERROR(@msg,0,1) С NOWAIT EXEC spDeleteUpdate @localUpdateID=@var1 
FETCH NEXT FROM WC INTO @var1 END 
ЗАКРЫТЬ ТУАЛЕТ 
УДАЛИТЬ ТУАЛЕТ 
УДАЛИТЬ ТАБЛИЦУ #results

--------------------------------------------- ----------------------------------------

6) Запустите приведенный ниже запрос, чтобы узнать нет. обновлений для XML длиной 5000 и более:

Выбрать 
  u.UpdateID, 
  r.RevisionNumber, 
  р.RevisionID,
  lp.Title, 
  pr.ExplicitlyDeployable как ED, 
  пр.UpdateType, 
  pr.CreationDate 
 от 
  tbОбновить 
  внутреннее соединение tbRevision r на u.LocalUpdateID = r.LocalUpdateID 
  внутреннее соединение tbProperty pr на pr.RevisionID = r.RevisionID 
  внутреннее соединение tbLocalizedPropertyForRevision lpr на r.RevisionID = lpr.RevisionID 
  внутреннее соединение tbLocalizedProperty lp на lpr.LocalizedPropertyID = lp.LocalizedPropertyID 
 куда 
  lpr.LanguageID = 1033 
  и r.RevisionID в (
Выбрать
  t1.RevisionID
от
  tbBundleAll t1
  внутреннее соединение tbBundleAtLeastOne t2 на t1.BundledID=t2.BundledID
куда
  t2.RevisionID in(SELECT dbo.tbXml.RevisionID FROM dbo.tbXml
ВНУТРЕННЕЕ СОЕДИНЕНИЕ dbo.tbProperty ON dbo.tbXml.RevisionID = dbo.tbProperty.RevisionID
где ISNULL (длина данных (dbo.tbXml.RootElementXmlCompressed), 0) > 50000) и ishidden = 0 и pr.ExplicitlyDeployable = 1)

--------------------------------------------- ---------------------------------------------

7) Если есть обновления, мы отклоняем их с помощью следующего курсора:

ОБЪЯВИТЬ @UpdateID nvarchar(100)
ОБЪЯВИТЬ @msg nvarchar(100)
 
CREATE TABLE #Updates (UpdateID nvarchar(100)) 
 
ВСТАВИТЬ В #Updates(UpdateID) 
Выбрать 
  u.UpdateID
  от 
  tbОбновить 
  внутреннее соединение tbRevision r на u.LocalUpdateID = r.LocalUpdateID 
  внутреннее соединение tbProperty pr на pr.RevisionID = r.RevisionID 
  внутреннее соединение tbLocalizedPropertyForRevision lpr на r.RevisionID = lpr.RevisionID 
  внутреннее соединение tbLocalizedProperty lp на lpr.LocalizedPropertyID = lp.LocalizedPropertyID 
 куда 
  lpr.LanguageID = 1033 
  и r.RevisionID в (
Выбрать
  t1.RevisionID
от
  tbBundleAll t1
  внутреннее соединение tbBundleAtLeastOne t2 на t1.BundledID=t2.BundledID
куда
  t2.RevisionID in(SELECT dbo.tbXml.RevisionID FROM dbo.tbXml
ВНУТРЕННЕЕ СОЕДИНЕНИЕ dbo.tbProperty ON dbo.tbXml.RevisionID = dbo.tbProperty.RevisionID
где ISNULL (длина данных (dbo.tbXml.RootElementXmlCompressed), 0) > 50000) и ishidden = 0 и pr.ExplicitlyDeployable = 1)
 
ОБЪЯВИТЬ Курсор UC
ЗА
ВЫБЕРИТЕ ID обновления из #Updates
 
ОТКРЫТЬ UC
ПОЛУЧИТЬ СЛЕДУЮЩУЮ ИЗ UC
В @UpdateID
ПОКА(@@FETCH_STATUS > -1)
BEGIN SET @msg = 'Отклонение' + @UpdateID
RAISERROR(@msg,0,1) С NOWAIT EXEC spDeclineUpdate @updateID=@UpdateID,@adminName=N'mach14\administrator',@failIfReplica=1 
 
ПОЛУЧИТЬ СЛЕДУЮЩИЙ ИЗ UC В @UpdateID END
ЗАКРЫТЬ

ОСВОБОДИТЬ UC
УДАЛИТЬ ТАБЛИЦУ #Обновления

--------------------------------------------- --------------------------------------------

8) Отказ от обновлений драйверов: -
 
ИСПОЛЬЗОВАТЬ ЮСДБ
ИДТИ
ВЫБЕРИТЕ UpdateTypeID ИЗ tbUpdateType, ГДЕ Имя = «Драйвер»
ИДТИ
 
удалить из tbrevisionlanguage, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629')) 
удалить из tbProperty, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbLocalizedPropertyForRevision, где идентификатор ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbFileForRevision, где идентификатор ревизии (выбрать идентификатор ревизии из tbRevision, где LocalUpdateId в (выбрать LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbInstalledUpdateSufficientForPrerequisite, где Prerequisiteid в (выбрать Prerequisiteid из tbPreRequisite, где id ревизии (выбрать id ревизии из tbRevision, где LocalUpdateId в (выбрать LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbPreRequisite, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbDeployment, где находится номер ревизии (выберите идентификатор версии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbXml, где находится номер ревизии (выберите номер ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbPreComputedLocalizedProperty, где идентификатор ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbDriver, где находится номер ревизии (выберите номер ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbFlattenedRevisionInCategory, где идентификатор ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbRevisionInCategory, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbMoreInfoURLForRevision, где идентификатор ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'))
удалить из tbRevision, где LocalUpdateId (выбрать LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629')
удалить из tbUpdateSummaryForAllComputers, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629')
 
 
удалить из tbUpdate, где UpdateTypeID = 'D2CB599A-FA9F-4AE9-B346-94AD54EE0629'


9) Удалить скрытые обновления:



ВЫБЕРИТЕ * ИЗ tbUpdate, ГДЕ isHidden = 1
 
удалить из tbrevisionlanguage, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbProperty, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbLocalizedPropertyForRevision, где идентификатор ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbFileForRevision, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden=1))
удалить из tbInstalledUpdateSufficientForPrerequisite, где Prerequisiteid в (выбрать Prerequisiteid из tbPreRequisite, где id ревизии в (выбрать id ревизии из tbRevision, где LocalUpdateId в (выбрать LocalUpdateId из tbUpdate, где ishidden = 1)))
удалить из tbPreRequisite, где находится ревизия (выберите ревизию из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden=1))
удалить из tbDeployment, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden=1))
удалить из tbXml, где находится номер ревизии (выберите номер ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden=1))
удалить из tbPreComputedLocalizedProperty, где идентификатор ревизии (выбрать идентификатор ревизии из tbRevision, где LocalUpdateId (выбрать LocalUpdateId из tbUpdate, где ishidden=1))
удалить из tbDriver, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbFlattenedRevisionInCategory, где идентификатор ревизии (выбрать идентификатор ревизии из tbRevision, где LocalUpdateId в (выбрать LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbRevisionInCategory, где находится номер ревизии (выбрать идентификатор ревизии из tbRevision, где LocalUpdateId в (выбрать LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbMoreInfoURLForRevision, где идентификатор ревизии (выбрать идентификатор ревизии из tbRevision, где LocalUpdateId в (выбрать LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbBundleAtLeastOne, где находится пакет (выберите пакетный идентификатор из tbBundleAll, где номер ревизии (выберите номер ревизии из tbRevision, где LocalUpdateId в (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbBundleAll, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbSecurityBulletinForRevision, где находится номер ревизии (выбрать номер ревизии из tbRevision, где LocalUpdateId (выбрать LocalUpdateId из tbUpdate, где ishidden=1))
удалить из tbKBArticleForRevision, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbRevisionSupersedesUpdate, где находится номер ревизии (выберите идентификатор ревизии из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbBundleAtLeastOne, где находится ревизия (выберите ревизию из tbRevision, где LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbEulaProperty, где находится ревизия (выбрать ревизию из tbRevision, где LocalUpdateId (выбрать LocalUpdateId из tbUpdate, где ishidden = 1))
удалить из tbRevision, где находится LocalUpdateId (выберите LocalUpdateId из tbUpdate, где ishidden=1)
удалить из tbUpdateSummaryForAllComputers, где LocalUpdateId (выбрать LocalUpdateId из tbUpdate, где ishidden=1)
удалить из tbInstalledUpdateSufficientForPrerequisite, где LocalUpdateId (выбрать LocalUpdateId из tbUpdate, где ishidden=1)
удалить из tbUpdate, где ishidden = 1 

--------------------------------------------- --------------------------------------------- --------------------------

Затем откройте консоль WSUS и перейдите в «Параметры\Мастер очистки сервера».
И запускайте мастера один за другим.
Michael Hampton avatar
флаг cz
Можно [опубликовать свои собственные знания](/help/self-answer), но они должны быть в формате вопроса и ответа, с вопросом выше и ответом ниже.
BitWrangler avatar
флаг jp
Отмеченный. Первый пост.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.