Чи настільки модернізовані оновлення SQL Server, як і раніше?


78

Я працюю з SQL-сервером і вимикаюсь ще з SQL Server 6.5, стара порада, яка все ще лунає в моїй голові, ніколи не робила оновлення на місці.

В даний час я модернізую свої системи RV DEV і TEST 2008 R2 до SQL Server 2012 і мені потрібно використовувати одне і те ж обладнання. Думка не потребувати відновлення моєї конфігурації служб Reporting дуже приваблива, і я справді проти стіни. Немає жодних служб аналізу чи чогось незвичайного чи нестандартного - встановлюється лише система бази даних та служби звітності.

Хтось стикався з серйозними проблемами з місцевими оновленнями? Або я повинен переоцінити свою позицію щодо оновлення на місці?


Я вирішив зробити оновлення на одному сервері з встановленням служб звітності. Єдине питання, з яким я зіткнувся, - це спроба використовувати інструмент експорту імпорту в SSMS з нативним клієнтом 11. Спроба перетворення не вдалася з помилкою щодо нерозпізнаних типів даних. Вирішення, яке я використав, було зберегти пакунок і запустити його в засобах передачі даних SQL (заміна 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 днів, тому ви не ставите себе в погану позицію, роблячи це.

Якщо ви плануєте робити місце для розробки / тестування, але хочете зробити міграцію для виробництва, ви можете розглянути можливість зробити хоча б одну міграцію перед виробництвом. Таким чином ви можете достроково опрацювати свій контрольний список і вирішити будь-які потенційні проблеми, про які ви не думали.

Приєднати / Від'єднати проти резервного копіювання / Відновити для міграцій

Якщо ви вирішите піти з міграційним підходом, все ж є ще одне рішення, щодо якого ви все ще можете обговорити, і саме так ви перемістите свою базу даних у нове середовище. Ви можете від'єднати свою базу даних від старого сервера та приєднати її до нового або створити резервну копію та відновити її там.

Я віддаю перевагу резервного копіювання / відновлення. Найбільша перевага, яку я чую про від'єднання / кріплення, - це те, що це економить деякий час. Для мене резервне копіювання / відновлення виграє з кількох причин:

  • Зберігайте старий доступним - це дозволяє вам все ще мати доступну базу даних на вихідному сервері. відокремлювати / прикріплювати слід так само, але для цього знадобиться кілька кроків, і є місце для людської помилки з від'єднанням / приєднанням, що може це ускладнити.
  • Ви гарантуєте, що у вас є резервна копія. Замість того, щоб просто брати базу даних з окремої частини та потенційно забути крок резервного копіювання, ви переконалися, що зробили цю резервну копію.
  • Людська помилка - Якщо ви видалите невірний файл, забудете, куди ви надсилаєте щось, або іншим чином зіпсуєте свої кроки, ви ризикуєте значно, перемістивши дані та файли журналів для вашої бази даних. Тепер ви можете пом'якшити це, скопіювавши замість вирізання (і якщо ви від'єднаєтесь, вам слід вийти з зрізу та вставити звичку), але ви могли б зіпсувати це. 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
Тільки якщо сховище також віртуалізоване і є частиною знімка. Якщо сховище буде безпосередньо приєднано до VM, воно не повернеться назад, коли знімок буде відновлено ...
Remus Rusanu

1

Через великі інвестиції в обладнання, від нас вимагали оновити тільки ОС, зберігаючи поточну версію SQL Server (2012, 3 сервери, 22 екземпляри, ~ 300 баз даних). Немає складних налаштувань, таких як дзеркальне відображення тощо.

Цей приклад не відповідає питанню, оскільки SQL Server не оновлюється. Я думаю, що це все-таки хороша відповідь, оскільки показані кроки насправді будуть простішими, ніж справжня міграція на місце.

Огляд: зовнішній накопичувач був приєднаний для повного резервного копіювання в основному в якості запобіжних заходів. Фактично відновлені лише модель та msdb із зовнішнього диска. Ldf / mdf залишили на місці для від'єднання / прикріплення. Деякі локальні облікові записи були посиланнями в БД. Після їх відновлення в ОС посилання в БД були відновлені (оскільки SID можуть змінюватися).

Потім були кроки, які працювали на нас:

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

2) Виправити SQL Server 2012 на SP3 (необхідна послідовність, якщо ми хочемо відновити будь-яку системну dbs).

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) Запустіть скрипт для резервного копіювання всіх БД, включаючи систему (майстер, MSDB, модель) на зовнішній диск.

6) Запустіть скрипт, щоб вилучити всі БД

7) Диск C буде переформатований. Збережіть LDF / MDF, якщо вони НЕ були на C.

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

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

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 AGENT.

(Чи змогли би відновити тут Майстра, ми вирішили).

15) Прикріпіть mdf / ldf, використовуючи скрипт зверху. а. Якщо не вдалося відновити вручну з Bak за допомогою сценарію зверху.

16) Спроба відновлення моделі

17) Переконайтеся, що агент SQL зупинений. Відновлення MSDB (посилання) a. Якщо не вдалося, потрібно заново створити завдання + план технічного обслуговування + конфігурація пошти + оператори

18) Відкрити сценарій для входу користувача ...

    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) Увімкніть сервісного брокера, щоб він відповідав початковому значенню SELECT імені, is_broker_enabled від 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

Що не вистачає:

  • Користувачі оригіналу в головній базі даних (рідко?)
  • Ролі сервера
  • ?

0

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

Якщо є проблема з міграційним підходом, це не технічно: це лінь. Занадто часто я знаходжу, що причина, поки компанія ще не перейшла повністю на ххх-версію, полягає в тому, що вони обрали розгорнуту міграцію і ніколи не обійшлися, щоб зробити важку роботу, щоб повністю переїхати. Тепер у них два або більше наборів серверів замість одного.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.