Являются ли обновления на месте SQL Server такими плохими советами, как раньше?

78

Я работаю с SQL-сервером, начиная с SQL Server 6.5, и старый совет, который до сих пор звучит в моей голове, никогда не состоял в обновлении на месте.

В настоящее время я модернизирую свои системы DEV R2 и TEST 2008 R2 до SQL Server 2012, и мне нужно использовать то же оборудование. Мысль о том, что мне не нужно восстанавливать конфигурацию моих служб отчетов, очень привлекательна, и я действительно настроен против стены. Там нет задействованных служб анализа или чего-то необычного или нестандартного - только ядро ​​базы данных и службы отчетов установлены.

Кто-нибудь испытывал серьезные проблемы с обновлениями на месте? Или я должен переоценить свою позицию относительно обновлений на месте?

Поврежденные товары
источник
Я решил сделать обновление на месте на 1 сервере с установкой служб отчетов. Единственной проблемой, с которой я столкнулся, была попытка использовать инструмент экспорта-импорта в SSMS с собственным клиентом 11. Попытка преобразования завершилась неудачно с ошибкой о нераспознанных типах данных. Обходной путь, который я использовал, состоял в том, чтобы сохранить пакет и запустить его в SQL Data Tools (замена BIDS), который работал нормально. Я думаю, что это должно быть связано с тем, что файл конфигурации для SSIS 2008 не перезаписывается. Это случилось со мной позже, вы можете просто сменить нативный клиент на 10.
DamagedGoods

Ответы:

92

Действительно короткий ответ - на месте все в порядке. После этого вы можете просмотреть свою конфигурацию и внедрить лучшие практики для SQL Server 2012.

Более длинный ответ на обновления / миграции SQL Server

Так что это вопрос мнений, и нет обязательно неправильного или правильного ответа, но я предпочитаю обновления стиля миграции по месту по многим причинам. При этом у некоторых моих клиентов по разным причинам не было иного выбора, кроме как сделать их на месте, и действительно, начиная с SQL Server 2005, обновления на месте не были такими плохими, как раньше.

Почему я предпочитаю переход на обновление на месте

  • Более простой откат - если что-то пойдет не так, вы можете откатить, просто сказав: «Мы прервали обновление. Пожалуйста, измените строки подключения на старый сервер, пока мы решаем эту проблему». С исправлением вы исправляете это, или вы не в себе.
  • Обновить оборудование - оборудование быстро меняется. Вы можете легко застрять на оборудовании, которое было подходящим для вашей компании 4 года назад, но не подходящим для сегодняшнего дня и последующих четырех лет с обновлением на месте. В любом случае вам, скорее всего, придется в какой-то момент выполнить миграцию для нового оборудования.
  • Чувствовать себя лучше - конечно ... Это субъективно, но приятно знать, что вы начинаете с новой установки ОС, новой установки SQL без паутины от человека, работавшего до вас (или до того, как вы узнали то, что знали сегодня), что может вызвать головную боль в будущем.
  • Новая ОС - Миграция дает вам возможность начать с новой версии ОС, если вы не используете последнюю и лучшую версию на сегодняшний день.
  • Вы можете проверить это - Вы когда-нибудь хотели получить набор базовых показателей на новом компьютере, прежде чем устанавливать SQL-сервер и использовать его для баз данных и использования? Вы можете сделать это сейчас.
  • В некоторых случаях легче подкрасться - возможно, учетная запись службы SQL Server была локальным администратором. Может быть, Builtin Administrators входит в роль сервера SA. Возможно, что-то было взломано вместе, чтобы заставить его работать раньше. Вы можете исправить это все и начать все заново.
  • Бесплатная тестовая среда и дополнительный сон. Выгодно иметь среду, в которой вы можете работать в преддверии настоящего рабочего дня, когда вы создаете новую среду. Выполнение перехода на новую среду означает, что вы можете создать его в рабочее время, значительно опередив свой реальный рабочий день, и заранее опробовать его во многих отношениях. Вы можете провести полное регрессионное тестирование во всех приложениях и системах в течение нескольких дней и иметь спокойствие перед тем, как приступить к окончательному набору операций восстановления / присоединения и переключения всех приложений и доступа к новой среде.
  • Вам не нужно делать все сразу - очень распространенная ситуация, с которой я сталкиваюсь, - это среда, которая пытается объединиться в несколько случаев. Возможно один на версию, возможно один на «уровень» и версию. Многие из этих проектов имеют разные временные рамки для различных приложений и баз данных на основе тестирования, планов проектов и своевременности сертификации поставщиков. Выполнение миграции означает, что вы можете переместить те базы данных, которые готовы, когда они готовы и все еще обрабатывают запросы для тех баз данных, которые не могут быть перемещены по той или иной причине.

Имейте в виду, я не говорю, что вы должны сделать это как миграцию. In-Place работает и работает хорошо, если вы не планируете покупать новое оборудование в своем бюджете и не можете сделать это для этого обновления. Поддержка в процессе обновления намного лучше, чем была за 6,5 дней, поэтому вы не ставите себя в плохое положение, делая это.

Если вы планируете делать на месте для dev / test, но хотите выполнить миграцию для рабочей среды, вы можете рассмотреть возможность выполнения хотя бы одной миграции перед производством. Таким образом, вы можете заранее составить свой контрольный список и решить любые потенциальные проблемы, о которых вы не задумывались.

Присоединение / Открепление или Резервное копирование / Восстановление для Миграций

Если вы решите использовать миграционный подход, есть еще одно решение, о котором вы все еще можете спорить, и именно так вы перенесете свою базу данных в новую среду. Вы можете либо отсоединить свою базу данных от старого сервера и прикрепить ее к новому, либо создать резервную копию и восстановить ее там.

Я предпочитаю резервное копирование / восстановление. Самое большое преимущество, которое я слышу о detach / attach - это то, что это экономит время. Для меня резервное копирование / восстановление выигрывает по нескольким причинам:

  • Оставить старый доступным - это позволяет вам иметь доступную базу данных на исходном сервере. detach / attach должна сделать то же самое, но это потребует нескольких шагов, и есть место для человеческой ошибки с detach / attach, которая может усложнить это.
  • Вы гарантируете, что у вас есть резервная копия - вместо того, чтобы просто взять базу данных из отсоединения и, возможно, забыть о шаге резервного копирования, вы убедились, что сделали эту резервную копию.
  • Человеческая ошибка - если вы удалите не тот файл, забудете, куда отправляете что-то или иным образом испортите свои шаги, вы сильно рискуете, перемещая данные и файлы журналов для своей базы данных. Теперь вы можете уменьшить это, копируя вместо вырезания (и если вы отсоединяетесь, вы должны избавиться от привычки вырезать и вставлять), но вы можете все испортить. SQL Server больше не блокирует эти файлы, и слишком просто случайно удалить файл, чтобы я рискнул им.
  • На самом деле это не так медленно - создание резервной копии и ее копирование занимает немного больше времени, но я не так много, чтобы платить за это дополнительным риском. Фактически - используя модель полного восстановления и резервные копии журналов, вы можете сократить время простоя для переключения, как описано ниже в разделе «Как ускорить подход к миграции».

Если вы решили выполнить резервное копирование / восстановление - это означает, что ваша старая исходная база данных все еще будет в сети. Мне нравится переводить эту базу данных в автономный режим после создания резервной копии. Иногда я захожу на шаг дальше и отключаю весь экземпляр SQL после того, как написал сценарий безопасности, заданий, связанного сервера, сертификатов, настроек почты базы данных и другой информации, относящейся ко всему экземпляру. Это позволяет избежать проблем во время тестирования, когда кто-то говорит: «Все выглядит отлично!» только через день или два понял, что они разговаривали со старой базой данных на старом сервере. Перевод этих баз данных в автономный режим или отключение всего экземпляра позволяет предотвратить ложные срабатывания и беспорядок, который они создают.

Как сделать миграционный подход быстрее

Вы можете минимизировать время простоя, необходимое для перехода со старой на новую среду для загруженной производственной среды с небольшим временем простоя, используя модель полного восстановления. По сути - подготовьте среду, в которую вы переходите, восстановив последнюю полную резервную копию, указав NORECOVERYвсе разностные резервные копии и все уже сделанные резервные копии журналов, - тогда все, что вам нужно будет сделать для окончательного сокращения, - это восстановить резервные копии журналов, которые еще не были восстановлены, и окончательная резервная копия журнала, которую вы хотите восстановить, указав WITH RECOVERY. Таким образом, для большой базы данных фактическое окно простоя может быть существенно минимизировано путем оплаты стоимости полного, разностного восстановления и восстановления большинства журналов до времени простоя. Спасибо Тао за то, что указал на это в комментариях!

Как сделать обновление на месте более безопасным

Несколько вещей, которые вы можете сделать, чтобы улучшить свой опыт и результаты при выборе подхода на месте.

  • Резервное копирование - Делайте соответствующие резервные копии всех пользовательских и системных баз данных вашей среды заблаговременно и убедитесь, что они хороши (я параноик. Я на самом деле восстановил бы их где-нибудь первым, чтобы действительно знать, что они хороши. Может быть, тратить ваше время). Но вы можете поблагодарить себя в случае аварии). Запишите любую конфигурационную информацию об установке SQL и ОС в этой среде.
  • Проверьте все перед началом работы - убедитесь, что у вас хорошая среда и хорошие базы данных. Вы должны делать такие вещи, как просмотр журналов ошибок и регулярный запуск DBCC CHECKDB, но перед обновлением на месте самое время начать. Исправьте любые проблемы заранее.
  • Обеспечьте работоспособность ОС - не только убедитесь, что SQL исправен, но и убедитесь, что ваш сервер исправен. Есть какие-то грубые ошибки в журналах событий вашей системы или приложения? Как ваше свободное место?
  • Готовьтесь к худшему - у меня недавно была серия постов в блоге, в которой говорилось, что если вы не готовитесь к неудаче - вы на самом деле готовитесь к неудаче ... Я все еще верю в это. Так что продумайте вопросы, которые могут у вас возникнуть, и решите их соответствующим образом заранее. Окунитесь в состояние «неудачи», и вы будете думать о вещах, которых у вас не было бы иначе.

Важность контрольных списков обновления или миграции

Если вы решили выполнить обновление (на месте или при переносе), вам следует серьезно подумать о создании контрольного списка и использовании этого контрольного списка в каждой среде. Вы должны включить кучу вещей в этот контрольный список, не в последнюю очередь из которых:

  1. На начальном этапе - выполните некоторые действия, такие как тестовое обновление, протестируйте свои приложения на последнем уровне совместимости баз данных и попробуйте заранее запустить инструмент, такой как советник по обновлению SQL Server, чтобы увидеть, какие задачи необходимо выполнить перед выполнением SQL. Обновление сервера или миграция.
  2. Предварительные шаги - очистка, задачи ОС, исправление заранее, подготовка приложений к обновлению (чистое завершение работы, работа со строкой подключения), резервное копирование и т. Д.
  3. Шаги обновления / миграции - все, что вам нужно сделать, чтобы обновление или миграция прошли успешно и в правильном порядке. Установка, изменение (или не изменение в зависимости от вашего тестирования и подхода) режима совместимости с базами данных и т. Д.
  4. Последующие этапы миграции / обновления - различные тесты, публикация новой версии или новых параметров конфигурации сервера, внедрение передового опыта, изменения безопасности и т. Д.
  5. Шаги отката - на протяжении всего пути вы должны иметь шаги и этапы отката. Если вы зайдете так далеко, и это произойдет, что вы будете делать? Каковы критерии «сделать полный откат»? И как вы выполняете этот откат (изменение строки обратного соединения, изменение настроек обратно, возврат к старой версии, переустановка, если она есть, указание на старый сервер при миграции и т. Д.)

Затем попросите человека, который будет выполнять модернизацию производства, следовать контрольному списку в какой-либо среде, отличной от производственной, особенно закрывающаяся, если это возможно, напоминает производственную (например, «К югу от производства») и отмечать любые проблемы или моменты. где они должны были отклониться от контрольного списка или импровизировать из-за отсутствия контрольного списка. Затем объедините изменения и повеселитесь с производственными изменениями.

Я не могу переоценить важность тщательного тестирования после перенастройки или апгрейда и до того, как вы перейдете к миграции. Решение об откате в процессе обновления должно быть простым, особенно во время миграции. Если есть что-то неудобное, откатитесь и выясните это, если вы не можете эффективно и надежно устранить неполадки в разгар миграции. Если вы живете в этой новой среде и пользователи подключаются, откат становится сложной задачей. Вы не можете восстановить базу данных SQL Server до более ранней версии. Это означает ручную работу и миграцию данных. Я всегда жду пару недель, чтобы убить старую среду, но вы должны сделать все возможное, чтобы избежать необходимости в этой старой среде, найти все свои проблемы, прежде чем ваши живые пользователи когда-либо коснутся новой среды. Желательно, прежде чем вы даже начать обновление / миграцию.

Краткое примечание о миграции / обновлении служб отчетов SQL Server. Миграция установки SSRS - не такая уж и сложная задача, как многие думают. Эта техническая / книжная онлайн-статья на самом деле очень удобна . Одним из наиболее важных указаний в этой статье является «Резервное копирование ключей шифрования», особенно если у вас много сохраненной конфиденциальной информации, такой как запланированные адреса электронной почты получателя отчета, информация о соединении для множества соединений и т. Д. Вы Я могу спросить одного из моих клиентов с недавнего времени, насколько это важно. Они знают, потому что я испортил этот шаг и потратил довольно много времени на изменение расписаний отчетов и разрешений строки подключения.

Майк Уолш
источник
14

По моему опыту, процесс принятия решений должен быть таким же, как и раньше. AFAIK Не было никаких «преобразователей мира» с установкой SQL Server, в самом продукте MS SQL Server, и с потенциальными проблемами, возникающими при развертывании программного обеспечения с миллионами строк кода. Может случиться что-то плохое, и теперь вы застряли без опции «ROLLBACK».

Однако у вас есть другие альтернативы. Вы можете сделать снимок системы, восстановить в другом месте, выполнить обновление и посмотреть, что произойдет. Этот тест должен дать вам много комфорта, но он не гарантирует, что на коробке с продуктом проблем не возникнет. Однако этот параметр недоступен в SQL 6.5 дней.

Я бы просто предположил худший вариант развития событий. Вы делаете обновление на месте, и оно терпит неудачу. Затем вы должны оправиться от этого в RTO и RCO. Понимает ли бизнес риски и есть ли у вас планы по его снижению?

Если с этим не все в порядке, то не советую.

Али Разеги
источник
2

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

Трой
источник
1
Только если хранилище также виртуализировано и является частью снимка. Если хранилище напрямую подключено к виртуальной машине, оно не будет «откатано» при восстановлении моментального снимка ...
Remus Rusanu
1

Из-за больших вложений в оборудование нам потребовалось обновить только ОС, сохранив текущую версию SQL Server (2012, 3 сервера, 22 экземпляра, ~ 300 баз данных). Нет сложных настроек, таких как зеркалирование и т. Д.

Этот пример не соответствует вопросу точно, так как SQL Server не обновляется. Я думаю, что это все еще хороший ответ, потому что показанные шаги были бы на самом деле проще, чем истинная миграция на месте.

Обзор: внешний диск был подключен для полного резервного копирования, главным образом, в качестве меры предосторожности. Только модель и msdb будут фактически восстановлены с внешнего диска. Ldf / mdf были оставлены на месте для открепления / прикрепления. Некоторые локальные учетные записи были указаны в БД. После того, как они были воссозданы в ОС, ссылки в БД были воссозданы (поскольку SID могут измениться).

Тогда вот шаги, которые работали для нас:

1) Запомните настройки уровня сервера, которые будут восстановлены в шагах 12 (Роли сервера) и с 18 по 23.

2) Исправление SQL Server 2012 с пакетом обновления 3 (требуется согласованность, если мы хотим восстановить какие-либо системные БД).

3) Проверьте соответствие версий на каждом экземпляре. «Выберите @@ версию»

4) Сгенерируйте эти 6 сценариев, запустив этот сценарий. Redgate SQL Multiscript позволяет сэкономить много времени, если имеется много экземпляров (установите Максимальные значения инструментов -> Параметры => Длина строки (8192), а затем используйте вывод текста).

  • Резервный
  • Восстановить
  • отрывать
  • Прикреплять
  • Воссоздать логины
  • Привязать пользователей к логинам

    -- (1) BACKUP / (2) RESTORE
    --    
    --*** SET THESE to external drive location
    --*** and create the Destination Directories
    declare 
        @backupInstanceDir  varchar(300) = 'F:\ExternalDriveBackups\' + replace(@@servername, '\', '_'),
        @dateSuffix         varchar(100) = '2015-12-14'; 
    
    if (object_id('tempdb..DatabaseStatus') is not null)
    drop table #DAtabseSTatus;
    
    select 
        d.name DbName, 
        d.state_desc DbState,
        d.user_access_desc UserMode,
        convert(bit, (d.is_read_only * -1 + 1)) as IsWritable,
        d.is_trustworthy_on as IsTrustWorthy,
        d.is_in_standby IsInStandby,
        d.recovery_model_desc RecoveryModel,
        suser_sname(d.owner_sid) as Owner,
        convert(bit, 
            case when d.database_id <= 4 or d.is_distributor = 1
                then 1
                else 0
            end) as IsSystemDb,
        mf.type_desc as FileType,
        mf.name FileName,
        mf.state FileState,
        mf.state_desc FileStatDesc,
        mf.physical_name PhysicalName,
        mf.type as FileTypeId    
    into #DatabaseStatus
    from
        sys.master_files AS mf
    join sys.databases AS d
    ON  mf.database_id = d.database_id
    where
        1=1
    order by
        d.name,
        mf.physical_name;
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutBU
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutRE
    
    create table #sqlOutBU
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    create table #sqlOutRE
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutBU select char(10) + '-- BACKUP SCRIPT' + char(10);
    insert into #sqlOutRE select char(10) + '-- RESTORE SCRIPT' + char(10);
    
    
    insert into #sqlOutBU select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOutRE select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';        
    
    PRINT '--Script for Backing up all DBs in a SQL Server Instance to a specific location' 
    
    SET nocount ON 
    
    insert into #sqlOutBU select char(10) + 
    '--' + char(10) + '-- BACKUP ' + @@servername + '--' + char(10) + 
    'use [Master]; set deadlock_priority high;' + char(10);
    
    insert into #sqlOutRE select '
    -- RESTORE
    --
    -- BE SURE TO BACKUP SYSTEM DBS TO AN ALTERNATE LOCATION JUST BEFORE RESTORING!
    --
    use [Master]; set deadlock_priority high;' + char(10);
    
    DECLARE @dbname nvarchar(128) 
    declare dblist_cursor cursor fast_forward for 
    select [name] from master.sys.databases where [name] != 'tempdb'
    order by iif(database_id <= 4, '0', '1') + [name]
    
    open dblist_cursor 
    fetch next from dblist_cursor into @dbname 
    
    while @@fetch_status = 0 
    begin 
    
        declare @bak nvarchar(300) = @backupInstanceDir + '\' + @dbname + '_' + @dateSuffix + '.bak';
    
        insert into #sqlOutBU select char(10) + 'backup database [' + @dbname + '] to disk = ''' + @bak + ''' WITH COPY_ONLY, NOFORMAT, NOINIT, ' + char(10) + 
            'NAME = N''' + @dbName + '-Full'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 25;';
    
        insert into #sqlOutRE select 'restore database [' + @dbName + '] from disk = ''' + @bak + ''' WITH FILE = 1,' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Rows' and DbName = @dbName
        ) + ',' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Log' and DbName = @dbName
        ) + ',' + char(10) +
        '    NOUNLOAD, REPLACE, STATS = 25;' + char(10);               
    
        fetch next from dblist_cursor into @dbname 
    end 
    
    close dblist_cursor 
    deallocate dblist_cursor 
    
    insert into #sqlOutBU select char(10) + 'go' + char(10);
    insert into #sqlOutRE select char(10) + 'go' + char(10);
    
    select Command from #sqlOutBU order by Row; -- BACKUP SCRIPT
    select Command from #sqlOutRE order by Row; -- RESTORE SCRIPT
    
    go
    
    
    
    --
    -- (3) DETACH  -  Org Author: Artemakis Artemiou
    --      
    
    if object_id('tempdb..#sqlOutDT') is not null
        drop table #sqlOutDT
    
    create table #sqlOutDT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutDT select char(10) + '-- DETACH all DBs from a SQL Server Instance' + char(10);      
    
    insert into #sqlOutDT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET nocount ON 
    
    insert into #sqlOutDT select char(10) + '--' + char(10) + '-- DETACH ' + @@servername + char(10) + '--' + char(10) + '
    use MAster; set deadlock_priority high;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128) 
    DECLARE dblist_cursor CURSOR fast_forward FOR 
    SELECT [name] 
    FROM   master.sys.databases 
    WHERE  database_id > 4 
    
    OPEN dblist_cursor 
    FETCH next FROM dblist_cursor INTO @dbname 
    
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
        insert into #sqlOutDT select
        'alter database ' + @dbname + ' set single_user with rollback immediate;' + char(10) +
        'EXEC sp_detach_db ''' + @dbname + ''', ''true'';' + char(10);
        FETCH next FROM dblist_cursor INTO @dbname 
    END 
    
    CLOSE dblist_cursor 
    DEALLOCATE dblist_cursor 
    
    insert into #sqlOutDT select char(10) + 'go' + char(10);
    select Command from #sqlOutDT order by Row;
    
    go
    
    
    
    --
    -- (4) ATTACH  -  Org Author: Artemakis Artemiou
    --    
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutAT
    
    create table #sqlOutAT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutAT select char(10) + '-- ATTACH ALL DBs to a SQL Server Instance' + char(10);
    
    insert into #sqlOutAT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET NOCOUNT ON
    
    insert into #sqlOutAT select char(10) + '--' + char(10) + '-- ATTACH ' + @@servername + char(10) + '--' + char(10) + 
    'use MAster;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128);
    
    DECLARE DBList_cursor CURSOR fast_forward FOR 
    select [name] from master.sys.databases where database_id > 4
    order by name;
    
    OPEN DBList_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
    declare @attach_TSQL_script varchar(max)
    set @attach_TSQL_script=''
    set @attach_TSQL_script=@attach_TSQL_script+'CREATE DATABASE ' + @dbname +' ON ' 
    
    declare @tsql varchar(max),@filename varchar(max)
    set @tsql='DECLARE DBFiles_cursor CURSOR FOR select [filename] from '+ @dbname + '.sys.sysfiles'
    
    execute (@tsql) 
    
    PRINT '--'+@dbname 
    
    OPEN DBFiles_cursor
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    
    WHILE @@FETCH_STATUS = 0
    BEGIN   
    set @attach_TSQL_script=@attach_TSQL_script+ char(10)+'    (FILENAME = '''+ @filename +'''),' 
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    END
    
    set @attach_TSQL_script=SUBSTRING(@attach_TSQL_script,0,len(@attach_TSQL_script))
    set @attach_TSQL_script=@attach_TSQL_script+ char(10) +'    FOR ATTACH;';
    
    insert into #sqlOutAT select @attach_TSQL_script + char(10);
    
    PRINT @attach_TSQL_script 
    PRINT ''
    
    CLOSE DBFiles_cursor
    DEALLOCATE DBFiles_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    END 
    
    CLOSE DBList_cursor
    DEALLOCATE DBList_cursor
    
    insert into #sqlOutAT select char(10) + 'go' + char(10);
    select Command from #sqlOutAT order by Row;
    go
    
    
    
    --
    -- (5) GENERATE A 'RE-CREATE LOGINS' SCRIPT
    --
    -- This script was modified from a version that was designed to copy from one server to another:
    --      http://stackoverflow.com/a/5983773/538763
    --
    
    
    USE [master]
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
    Command nvarchar(max) not null,
    Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RECREATE LOGINS' + char(10);
    
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOut select 'use Master;' + char(10);
    go
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    declare @Debug bit = 0;
    declare @PartnerServer varchar(100) = @@SERVICENAME;  -- use current server before it is shutdown (disabled below)
    
    declare
        @MaxID int,
        @CurrID int,
        @SQL nvarchar(max),
        @LoginName sysname,
        @IsDisabled int,
        @Type char(1),
        @SID varbinary(85),
        @SIDString nvarchar(100),
        @PasswordHash varbinary(256),
        @PasswordHashString nvarchar(300),
        @RoleName sysname,
        @Machine sysname,
        @PermState nvarchar(60),
        @PermName sysname,
        @Class tinyint,
        @MajorID int,
        @ErrNumber int,
        @ErrSeverity int,
        @ErrState int,
        @ErrProcedure sysname,
        @ErrLine int,
        @ErrMsg nvarchar(2048);
    
    declare @Logins Table (LoginID int identity(1, 1) not null primary key,
                        [Name] sysname not null,
                        [SID] varbinary(85) not null,
                        IsDisabled int not null,
                        [Type] char(1) not null,
                        PasswordHash varbinary(256) null)
    declare @Roles Table (RoleID int identity(1, 1) not null primary key,
                    RoleName sysname not null,
                    LoginName sysname not null)
    declare @Perms Table (PermID int identity(1, 1) not null primary key,
                    LoginName sysname not null,
                    PermState nvarchar(60) not null,
                    PermName sysname not null,
                    Class tinyint not null,
                    ClassDesc nvarchar(60) not null,
                    MajorID int not null,
                    SubLoginName sysname null,
                    SubEndPointName sysname null)
    
    Set NoCount On;
    
    If CharIndex('\', @PartnerServer) > 0
    Begin
    Set @Machine = LEFT(@PartnerServer, CharIndex('\', @PartnerServer) - 1);
    End
    Else
    Begin
    Set @Machine = @PartnerServer;
    End
    
    -- Get all Windows logins from principal server
    Set @SQL = 'Select P.name, P.sid, P.is_disabled, P.type, L.password_hash' + CHAR(10) +
        'From ' /*+ QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals P' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.sql_logins L On L.principal_id = P.principal_id' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'and P.Name Not like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;';
    
    Insert Into @Logins (Name, SID, IsDisabled, Type, PasswordHash)
    Exec sp_executesql @SQL;
    
    -- Get all roles from principal server
    Set @SQL = 'Select RoleP.name, LoginP.name' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_role_members RM' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + .*/ +'master.sys.server_principals RoleP' +
        CHAR(10) + char(9) + 'On RoleP.principal_id = RM.role_principal_id' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals LoginP' +
        CHAR(10) + char(9) + 'On LoginP.principal_id = RM.member_principal_id' + CHAR(10) +
        'Where LoginP.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And LoginP.name <> ''sa''' + CHAR(10) +
        'And LoginP.name Not Like ''##%''' + CHAR(10) +
        'And LoginP.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And RoleP.type = ''R''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', LoginP.name) = 0;';
    
    Insert Into @Roles (RoleName, LoginName)
    Exec sp_executesql @SQL;
    
    -- Get all explicitly granted permissions
    Set @SQL = 'Select P.name Collate database_default,' + CHAR(10) +
        '   SP.state_desc, SP.permission_name, SP.class, SP.class_desc, SP.major_id,' + CHAR(10) +
        '   SubP.name Collate database_default,' + CHAR(10) +
        '   SubEP.name Collate database_default' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals P' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_permissions SP' + CHAR(10) +
        CHAR(9) + 'On SP.grantee_principal_id = P.principal_id' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals SubP' + CHAR(10) +
        CHAR(9) + 'On SubP.principal_id = SP.major_id And SP.class = 101' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.endpoints SubEP' + CHAR(10) +
        CHAR(9) + 'On SubEP.endpoint_id = SP.major_id And SP.class = 105' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'And P.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;'
    
    Insert Into @Perms (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
    Exec sp_executesql @SQL;
    
    --select * from @Logins;
    --select * from @Roles;
    --select * from @perms;
    
    
    Select @MaxID = Max(LoginID), @CurrID = 1
    From @Logins;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = Name,
        @IsDisabled = IsDisabled,
        @Type = [Type],
        @SID = [SID],
        @PasswordHash = PasswordHash
    From @Logins
    Where LoginID = @CurrID;
    
    --    If Not Exists (Select 1 From sys.server_principals
    --              Where name = @LoginName)
    Begin
    
        set @sql = char(10);
        set @sql += 'If Not Exists (Select 1 From sys.server_principals Where name = ''' + @LoginName + ''')' + char(10);
        set @sql += 'begin' + char(10) + '    ';
    
        Set @SQL += 'Create Login ' + quotename(@LoginName)
        If @Type In ('U', 'G')
        Begin
            Set @SQL = @SQL + ' From Windows;'
        End
        Else
        Begin
            Set @PasswordHashString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@PasswordHash"))', 'nvarchar(300)');
    
            Set @SQL = @SQL + ' With Password = ' + @PasswordHashString + ' HASHED;  --, ';
    
            Set @SIDString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@SID"))', 'nvarchar(100)');
            Set @SQL = @SQL + 'SID = ' + @SIDString + ';' + char(10);
        End
    
        set @sql += char(10) +
            '    print ''Created Login ' + @loginName  + ''';' + char(10) +
            'end' + char(10) +
            'else' + char(10) +
            convert(nvarchar(max), '    print ''Login ' + @loginName + ' already existed. '';') + char(10);
    
        If @Debug = 0
        insert into #sqlOut select @SQL;                      
        Else
        Print @SQL;
    
        If @IsDisabled = 1
        Begin
            Set @SQL = 'Alter Login ' + quotename(@LoginName) + ' Disable;'
            If @Debug = 0
                insert into #sqlOut select @SQL;                              
            Else              
                Print @SQL;              
        End
        End
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    Select @MaxID = Max(RoleID), @CurrID = 1
    From @Roles;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = LoginName,
        @RoleName = RoleName
    From @Roles
    Where RoleID = @CurrID;
    
    /*  If Not Exists (Select 1 From sys.server_role_members RM
                Inner Join sys.server_principals RoleP
                    On RoleP.principal_id = RM.role_principal_id
                Inner Join sys.server_principals LoginP
                    On LoginP.principal_id = RM.member_principal_id
                Where LoginP.type In ('U', 'G', 'S')
                And RoleP.type = 'R'
                And RoleP.name = @RoleName
                And LoginP.name = @LoginName)*/
    Begin
        If @Debug = 0
        Begin          
            insert into #sqlOut select 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''', @loginame = ''' + @LoginName + ''';';
        End
        Else
        Begin
            Print 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''',';
            Print '     @loginame = ''' + @LoginName + ''';';
        End
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    
    Select @MaxID = Max(PermID), @CurrID = 1
    From @Perms;
    
    While @CurrID <= @MaxID
    Begin
    Select @PermState = PermState,
        @PermName = PermName,
        @Class = Class,
        @LoginName = LoginName,
        @MajorID = MajorID,
        @SQL = PermState + space(1) + PermName + SPACE(1) +
            Case Class When 101 Then 'On Login::' + QUOTENAME(SubLoginName)
                    When 105 Then 'On ' + ClassDesc + '::' + QUOTENAME(SubEndPointName)
                    Else '' End +
            ' To ' + QUOTENAME(LoginName) + ';'
    From @Perms
    Where PermID = @CurrID;
    
    /*If Not Exists (Select 1 From sys.server_principals P
                Inner Join sys.server_permissions SP On SP.grantee_principal_id = P.principal_id
                Where SP.state_desc = @PermState
                And SP.permission_name = @PermName
                And SP.class = @Class
                And P.name = @LoginName
                And SP.major_id = @MajorID)*/
    Begin
        If @Debug = 0
                insert into #sqlOut select @sql;                      
        Else          
            Print @SQL;          
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    select Command from #sqlOut as SqlOut order by Row;
    go
    
    
    --
    -- (6) Generate a script to Re-link all users to logins based on current state (before shutdown)
    --
    
    use Master;
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RELINK USERS TO LOGINS' + char(10);
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    declare @dbCmd varchar(8000) = '
    use ?;
    
    insert into #sqlOut select char(10) + ''use ?;'' + char(10);  
    
    with links as
    (
    select u.name as UserName,
        l.loginname as LoginName
        from sysusers u 
        join master..syslogins l
        on u.sid = l.sid        
    where u.name != ''dbo''
        and u.isSqlUser = 1 or l.isNtName = 1 or l.isNtGroup = 1
    )
    insert into #sqlOut 
    select ''alter user ['' + UserName + ''] with name = ['' + UserName + ''], login = ['' + LoginName + '']''
    from links
    ';    
    
    exec sp_MSforeachdb @dbCmd;
    
    select Command from #sqlOut order by Row;
    
    go

5) Запустите скрипт для резервного копирования всех БД, включая систему (master, msdb, модель), на внешний диск.

6) Запустите скрипт, чтобы отсоединить все БД

7) C диск будет переформатирован. Сохраните LDF / MDF, если они НЕ были на C.

8) Windows Server 2012 установлен на C

9) Переместите LDF / MDF для оригинальных системных файлов, если их не было на диске C.

10) SQL Server 2012 будет переустановлен и исправлен до SP3 a. Пересоздать системные учетные записи пользователей / групп

11) Резервное копирование системных БД в новое место или имя файла (будьте осторожны, чтобы не перезаписать оригиналы!).

12) Запустить воссоздание ролей ролей. Что-то вроде:

USE [master]
CREATE SERVER ROLE [SomeServerRole]
--ALTER SERVER ROLE [dbcreator] ADD MEMBER [SomeServerRole]
--ALTER SERVER ROLE [bulkadmin] ADD MEMBER [SomeServerRole]
-- ALTER SERVER ROLE [SomeServerRole] ADD MEMBER [SomeMemberOrRole]

13) Запустить сценарий повторного входа в систему (ничего не делает, если логины были восстановлены)

14) Стоп SQL АГЕНТ.

(Могли восстановить Мастера здесь, мы скушались).

15) Присоедините mdf / ldf, используя скрипт сверху. а. В случае неудачи восстановите вручную из bak, используя скрипт сверху.

16) Попытка восстановления модели

17) Убедитесь, что агент SQL остановлен. Восстановить MSDB (ссылка) a. Если не получится, нужно заново создать рабочие места + план обслуживания + настройки почты + операторы

18) Скрипт Open User To Login ...

    a. If there are master users (rare?) then First Re-Create users for master since it was not restored:
        use master;       
        CREATE USER [ABC] FOR LOGIN [machine\ABC]

    b. Run the rest of the script

19) Включите компонент Service Broker, чтобы он соответствовал исходному значению SELECT name, is_broker_enabled FROM sys.databases;

    alter database MSDB set single_user with rollback immediate;
    ALTER DATABASE [MSDB] SET ENABLE_BROKER;
    alter database MSDB set multi_user;

20) Запустите агент SQL

21) Установите порог параллелизма на исходное значение

22) Настройте любые параметры базы данных на исходные значения:

 declare @dbCmd varchar(8000) = '
      use ?;
      if db_name() not in (''master'', ''model'', ''tempdb'', ''msdb'')
      begin
             print ''Adjusting [?]...'';    
            alter database [?] set single_user with rollback immediate;
             aLTER AUTHORIZATION ON DATABASE::[?] to [sa];
            -- alter database [?] set trustworthy on;
            ALTER DATABASE [?] SET AUTO_CLOSE OFF WITH NO_WAIT;     
            alter database [?] set multi_user;
      end     
      else
             print ''Skipping [?]...'';
    ';    

    exec sp_MSforeachdb @dbCmd;

23) Проверьте право собственности на работу:

select s.name as JobName, l.name as login, SUSER_SNAME(s.owner_sid) AS login2
from  msdb..sysjobs s 
left join master.sys.syslogins l on s.owner_sid = l.sid

Если бы версия SQL Server также была обновлена, я не верю, что базы данных модели и базы данных msdb могли быть восстановлены, поэтому задания могли быть потеряны из-за https://support.microsoft.com/en-us/kb/264474.

Чего не хватает:

  • Оригинальные пользователи в основной базе данных (редко?)
  • Роли сервера
  • ?
crokusek
источник
0

Нет ничего плохого в любом подходе как таковом - я сделал оба, и оба результата, как правило, хороши.

Если есть проблема с миграционным подходом, это не техническая проблема: это лень. Слишком часто я обнаруживаю, что причина, по которой компания еще не полностью перешла на версию xxxx, заключается в том, что они выбрали свинг-миграцию и никогда не удосужились выполнить тяжелую работу, чтобы полностью перейти. Теперь у них есть два или более набора серверов вместо одного.

RowlandG
источник