Czy uaktualnienia na miejscu programu SQL Server są tak odradzane, jak kiedyś?

78

Pracuję z włączaniem i wyłączaniem serwera SQL od wersji SQL Server 6.5, stara rada, która wciąż dzwoni w mojej głowie, to nigdy nie robić aktualizacji na miejscu.

Obecnie aktualizuję moje systemy DEV i TEST 2008 R2 do SQL Server 2012 i muszę używać tego samego sprzętu. Myśl o tym, że nie muszę przywracać mojej konfiguracji usług raportowania, jest bardzo atrakcyjna i naprawdę nie mogę się doczekać, aby zrobić to z wyprzedzeniem. Nie ma w tym żadnych usług analitycznych ani niczego nietypowego lub niestandardowego - instalowane są tylko silnik bazy danych i usługi raportowania.

Czy ktoś doświadczył poważnych problemów z uaktualnieniami na miejscu? Czy powinienem ponownie ocenić swoje stanowisko w sprawie ulepszeń na miejscu?

Zniszczone dobra
źródło
Zdecydowałem się na uaktualnienie w miejscu na 1 serwerze z instalacją usług raportowania. Jedyny problem, na jaki natknąłem się, to próba użycia narzędzia importu eksportu w SSMS z rodzimym klientem 11. Próba transformacji nie powiodła się z błędem dotyczącym nierozpoznanych typów danych. obejściem, którego użyłem, było zapisanie pakietu i uruchomienie go w Narzędziach danych SQL (zastąpienie BIDS), które działały dobrze. Myślę, że musi to mieć związek z tym, że plik konfiguracyjny dla SSIS 2008 nie jest nadpisywany. Przyszło mi do głowy później, możesz po prostu zmienić klienta natywnego z powrotem na 10.
DamagedGoods

Odpowiedzi:

92

Naprawdę krótka odpowiedź - na miejscu jest w porządku. Następnie możesz przejrzeć swoją konfigurację i wdrożyć najlepsze praktyki dotyczące programu SQL Server 2012.

Dłuższa odpowiedź na temat aktualizacji / migracji SQL Server

Jest to więc opinia i niekoniecznie jest to zła lub prawidłowa odpowiedź, ale z wielu powodów wolę aktualizacje stylu migracji niż na miejscu. To powiedziawszy - niektórzy z moich klientów z różnych powodów nie mieli wyboru, musieli zrobić to na miejscu, a tak naprawdę od SQL Server 2005, aktualizacje na miejscu nie były tak złe, jak kiedyś.

Dlaczego wolę migrację niż uaktualnienie na miejscu

  • Łatwiejsze wycofywanie - jeśli coś pójdzie nie tak, możesz cofnąć, mówiąc „przerwaliśmy aktualizację. Podczas rozwiązywania problemu zmień parametry połączenia na stary serwer”. W miejscu naprawiasz go lub jesteś w dół.
  • Odśwież sprzęt - sprzęt zmienia się szybko. Możesz łatwo utknąć na sprzęcie, który był odpowiedni dla Twojej firmy 4 lata temu, ale nie na dziś i przez następne cztery lata dzięki aktualizacji na miejscu. Prawdopodobnie w pewnym momencie będziesz musiał przeprowadzić migrację nowego sprzętu.
  • Poczuj się lepiej - Jasne ... Ten jest subiektywny, ale dobrze jest wiedzieć, że zaczynasz od nowej instalacji systemu operacyjnego, nowej instalacji SQL bez pajęczyny od osoby w pracy przed tobą (lub zanim wiedziałeś, co wiesz) dzisiaj), co może powodować bóle głowy w przyszłości.
  • Nowy system operacyjny - migracja daje możliwość rozpoczęcia pracy z nową wersją systemu operacyjnego, jeśli nie masz najnowszej i najlepszej wersji.
  • Możesz to przetestować - Czy kiedykolwiek chciałeś uzyskać zestaw linii bazowych na nowej maszynie, zanim zainstalujesz SQL i zachmurzysz go bazami danych i użyciem? Możesz to zrobić teraz.
  • Czasami łatwiej jest podejść do najlepszych praktyk - być może konto usługi SQL Server było lokalnym administratorem. Być może wbudowani administratorzy pełnią rolę serwera SA. Może coś zostało zhakowane razem, żeby działało wcześniej. Możesz to wszystko naprawić i zacząć od nowa.
  • Bezpłatne środowisko testowe i dodatkowy sen - wielką korzyścią jest posiadanie środowiska, w którym można pracować przed faktycznym dniem przejścia na nowy system. Przeprowadzenie migracji do nowego środowiska oznacza, że ​​możesz go zbudować w godzinach pracy, na długo przed faktycznym dniem przejścia i przetestować na wiele sposobów z wyprzedzeniem. Możesz przeprowadzać pełne testy regresji dla wszystkich aplikacji i systemów przez kilka dni i mieć spokój, zanim faktycznie wykonasz końcowy zestaw przywracania / dołączania i przełączania wszystkich aplikacji i dostępu do nowego środowiska.
  • Nie musisz robić tego wszystkiego naraz - bardzo częstą sytuacją, w której wpadam, jest środowisko, które próbuje się skonsolidować tylko w kilku przypadkach. Być może jeden na wersję, może jeden na „poziom” i wersję. Wiele z tych projektów ma różne ramy czasowe dla różnych aplikacji i baz danych w oparciu o testy, plany projektów i terminowość certyfikacji dostawców. Przeprowadzenie migracji oznacza, że ​​możesz przenieść te bazy danych, które są gotowe, gdy są one gotowe i nadal obsługują żądania dotyczące tych baz danych, które nie mogą się przenieść z tego czy innego powodu.

Pamiętaj, że nie mówię, że musisz to zrobić jako migracja. Na miejscu działa i działa dobrze, jeśli nie planujesz zakupu nowego sprzętu w swoim budżecie i nie możesz tego zrobić w przypadku tej aktualizacji. Wsparcie w procesie aktualizacji jest o wiele lepsze niż w 6,5 dni, więc nie narażasz się na to, robiąc to.

Jeśli planujesz zrobić w miejscu na potrzeby tworzenia / testowania, ale chcesz przeprowadzić migrację dla produkcji, możesz rozważyć wykonanie przynajmniej jednej migracji przed produkcją. W ten sposób możesz wcześniej opracować listę kontrolną i rozwiązać wszelkie potencjalne problemy, o których nie myślałeś.

Dołącz / Odłącz vs. Kopia zapasowa / Przywróć dla migracji

Jeśli zdecydujesz się na migrację, jest jeszcze jedna decyzja, nad którą możesz jeszcze debatować. W ten sposób przeniesiesz bazę danych do nowego środowiska. Możesz odłączyć bazę danych od starego serwera i dołączyć ją do nowej lub utworzyć kopię zapasową i przywrócić ją tam.

Wolę tworzenie kopii zapasowych / przywracanie. Największą zaletą, którą słyszę o odłączaniu / dołączaniu, jest to, że oszczędza to trochę czasu. Dla mnie tworzenie kopii zapasowych / przywracanie wygrywa z kilku powodów:

  • Zachowaj stary dostępny - pozwala to nadal mieć dostępną bazę danych na serwerze źródłowym. odłączanie / dołączanie powinno zrobić to samo, ale będzie to wymagało kilku kroków i jest miejsce na błąd ludzki z odłączaniem / dołączaniem, który może to skomplikować.
  • Gwarantujesz, że masz kopię zapasową - Zamiast po prostu odłączyć bazę danych od odłączenia i potencjalnie zapomnieć o kroku tworzenia kopii zapasowej, masz pewność, że wykonałeś kopię zapasową.
  • Błąd ludzki - jeśli usuniesz niewłaściwy plik, zapomnisz, gdzie coś wysyłasz lub w inny sposób naruszysz swoje kroki, ryzykujesz dużo, przenosząc dane i pliki dziennika do bazy danych. Teraz możesz to złagodzić, kopiując zamiast wycinać (a jeśli się odłączysz, powinieneś porzucić nawyk wycinania i wklejania), ale wciąż możesz popsuć bałagan. SQL Server nie blokuje już tych plików i zbyt łatwo jest przypadkowo usunąć plik, aby zaryzykować.
  • To naprawdę nie jest , że wolniej - Wykonywanie kopii zapasowych i kopiowania jest to trochę więcej czasu, ale to nie jest tak dużo, że jestem gotów zapłacić dodatkowe ryzyko dla niego. W rzeczywistości - korzystając z pełnego modelu odzyskiwania i kopii zapasowych dzienników, możesz zmniejszyć czas przestoju w przypadku przełączeń, jak opisano poniżej w „Jak przyspieszyć podejście do migracji”

Jeśli zdecydujesz się wykonać kopię zapasową / przywracanie - oznacza to, że Twoja stara źródłowa baza danych będzie nadal w trybie online. Lubię robić tę bazę danych offline po zrobieniu kopii zapasowej. Czasami idę o krok dalej i wyłączam całą instancję SQL w trybie offline po tym, jak wykonałem skrypt bezpieczeństwa, zadań, połączonego serwera, certyfikatów, ustawień poczty bazy danych i innych informacji dotyczących całej instancji. Pozwala to uniknąć problemu podczas testowania, w którym ktoś mówi: „Wszystko wygląda świetnie!” tylko dzień lub dwa później uświadomili sobie, że rozmawiają ze starą bazą danych na starym serwerze. Przełączenie tych baz danych w tryb offline lub całej instancji w tryb offline pozwala zapobiec fałszywym pozytywom i bałaganowi, który popełniają.

Jak sprawić, by podejście do migracji było szybsze

Można zminimalizować czas przestoju wymagany do przejścia ze starego do nowego środowiska dla pracowitego środowiska produkcyjnego z niewielkim czasem przestoju dzięki wykorzystaniu pełnego modelu odzyskiwania. Zasadniczo - skonfiguruj środowisko, do którego migrujesz, przywracając najnowszą pełną kopię zapasową, wszelkie różnicowe kopie zapasowe i wszelkie już wykonane kopie zapasowe dzienników, określając NORECOVERY- wtedy wszystko, co musisz zrobić dla ostatecznego odcięcia, to przywrócić kopie zapasowe dziennika, które nie zostały jeszcze przywrócone i ostatnia kopia zapasowa dziennika, którą chcesz przywrócić, określając WITH RECOVERY. W ten sposób w przypadku dużej bazy danych rzeczywiste okno przestoju można znacznie drastycznie zminimalizować, płacąc za koszt pełnego, różnicowego i większości przywracania dziennika przed oknem przestoju. Dzięki Tao za wskazanie tego w komentarzach!

Jak uczynić aktualizację na miejscu bezpieczniejszą

Kilka rzeczy, które możesz zrobić, aby poprawić swoje wrażenia i wyniki, wybierając podejście na miejscu.

  • Kopia zapasowa - Zrób odpowiednie kopie zapasowe wszystkich baz danych użytkowników i systemu w swoim środowisku z wyprzedzeniem i upewnij się, że są one dobre (jestem paranoikiem. Naprawdę przywrócę je gdzieś, aby naprawdę wiedzieć, że są dobre. Może to być marnowanie twojego czasu. Ale możesz podziękować sobie w przypadku awarii). Skryptuj wszelkie informacje konfiguracyjne dotyczące instalacji SQL i systemu operacyjnego w tym środowisku.
  • Testuj dobrze przed rozpoczęciem pracy - sprawdź, czy masz dobre środowisko i dobre bazy danych. Powinieneś robić rzeczy takie jak przeglądanie dzienników błędów i regularne uruchamianie DBCC CHECKDB, ale przed wykonaniem aktualizacji w miejscu jest świetny czas na rozpoczęcie. Napraw wszelkie problemy z wyprzedzeniem.
  • Zapewnij zdrowie systemu operacyjnego - nie tylko upewnij się, że SQL jest zdrowy, upewnij się, że serwer jest zdrowy. Jakieś poważne błędy w dziennikach zdarzeń błędów systemu lub aplikacji? Jaka jest twoja wolna przestrzeń?
  • Przygotuj się na najgorsze - jakiś czas temu miałem serię postów na blogu, która opierała się na założeniu, że jeśli nie przygotowujesz się do porażki - tak naprawdę przygotowujesz się do porażki . Nadal w to wierzę. Zastanów się, jakie problemy możesz napotkać i odpowiednio się z nimi uporaj. Wejdź w sposób myślenia „porażki”, a pomyślisz o rzeczach, których inaczej byś nie miał.

Znaczenie uaktualnienia lub migracji list kontrolnych

Jeśli zdecydujesz się na aktualizację (na miejscu lub w migracji), powinieneś poważnie rozważyć utworzenie listy kontrolnej i korzystanie z tej listy kontrolnej w każdym środowisku. Na tej liście kontrolnej powinieneś znaleźć kilka rzeczy, z których przynajmniej:

  1. Na początku - wykonaj kilka czynności, takich jak aktualizacja testowa, przetestuj aplikacje na najnowszym poziomie zgodności z bazą danych i rozważ wcześniejsze uruchomienie narzędzia, takiego jak Doradca uaktualnienia programu SQL Server, aby zobaczyć, jakie zadania należy wykonać przed wykonaniem SQL Aktualizacja lub migracja serwera.
  2. Wstępne kroki - czyszczenie, zadania systemu operacyjnego, łatanie z wyprzedzeniem, przygotowywanie aplikacji do aktualizacji (czyste zamykanie, praca ciągu połączenia), kopie zapasowe itp.
  3. Kroki aktualizacji / migracji - Wszystko, co musisz zrobić, aby aktualizacja lub migracja zakończyła się powodzeniem i we właściwej kolejności. Instalacja, zmiana (lub brak zmian w zależności od testowania i podejścia) zmiany trybu zgodności w bazach danych itp.
  4. Kroki po migracji / aktualizacji - różne testy, opublikuj nową wersję lub nowe opcje konfiguracji serwera, wdrożenie najlepszych praktyk, zmiany bezpieczeństwa itp.
  5. Kroki wycofania - po drodze powinieneś mieć kroki wycofania i kamienie milowe. Jeśli dojdziesz tak daleko i tak się stanie, co zrobisz? Jakie są kryteria „wykonaj pełne wycofanie”? Jak to zrobić (wycofanie zmian ciągu połączenia, zmiana ustawień wstecz, powrót do starej wersji, ponowna instalacja, jeśli jest na miejscu, powrót do starego serwera w przypadku migracji itp.)

Następnie osoba, która będzie przeprowadzać aktualizację produkcji, postępuje zgodnie z listą kontrolną w niektórych środowiskach innych niż produkcja - zwłaszcza ta, która zamyka się, jeśli to możliwe, przypomina produkcję („Na południe od prod”, jak mówię ...) i odnotowuje wszelkie problemy lub punkty gdzie musieli odejść od listy kontrolnej lub improwizować z powodu braku listy kontrolnej. Następnie połącz zmiany i baw się dobrze ze zmianą produkcji.

Nie mogę przecenić znaczenia dokładnego testowania po migracji lub aktualizacji i wyprzedzania migracji. Podjęcie decyzji o wycofaniu w trakcie aktualizacji powinno być łatwe - szczególnie podczas migracji. Jeśli jest coś niewygodnego, wycofaj się i dowiedz się, czy nie możesz rozwiązać problemu skutecznie i niezawodnie w trakcie migracji. Po uruchomieniu nowego środowiska i nawiązaniu połączenia przez użytkowników wycofywanie staje się trudnym zadaniem. Nie można przywrócić bazy danych SQL Server do wcześniejszej wersji. Oznacza to pracę ręczną i migrację danych. Zawsze czekam kilka tygodni, aby zabić stare środowisko, ale powinieneś zrobić wszystko, aby uniknąć potrzeby korzystania ze starego środowiska, znajdując wszystkie swoje problemy, zanim Twoi użytkownicy na żywo dotkną nowego środowiska. Najlepiej zanim rozpoczniesz aktualizację / migrację.

Szybka uwaga na temat migracji / aktualizacji SQL Server Reporting Services Migracja instalacji SSRS nie jest herculeańskim zadaniem, jak wielu uważa. Ten artykuł online z technetem / książkami jest naprawdę przydatny . Jednym z najważniejszych ostrzeżeń w tym artykule jest „Utwórz kopię zapasową kluczy szyfrowania”, zwłaszcza jeśli masz wiele zapisanych poufnych informacji, takich jak adres e-mail odbiorcy zaplanowanego raportu, informacje o połączeniu dla wielu połączeń itp. mogę od pewnego czasu zapytać jednego z moich klientów, jak ważne jest to. Wiedzą, ponieważ pomieszałem ten krok i spędziłem sporo czasu modyfikując harmonogramy raportów i uprawnienia do ciągów połączeń.

Mike Walsh
źródło
14

Z mojego doświadczenia wynika, że ​​taki sam proces decyzyjny powinien być podejmowany wcześniej. AFAIK nie było żadnych „zmieniaczy świata” z instalacją SQL Server, w samym produkcie MS SQL Server, i potencjalnych problemów, jakie masz przy wdrażaniu oprogramowania z milionami linii kodu. Coś złego może się zdarzyć, a teraz utkniesz bez opcji „ROLLBACK”.

Masz jednak inne alternatywy. Możesz rozważyć wykonanie migawki systemu, przywrócenie go w innym miejscu, wykonanie aktualizacji i zobacz, co się stanie. Ten test powinien dać ci duży komfort, ale nie gwarantuje absolutnie żadnych problemów na pudełku produkcyjnym. Jest to jednak opcja, która nie była dostępna w SQL 6.5 dni.

Po prostu przyjąłbym najgorszy scenariusz. Wykonujesz uaktualnienie na miejscu, które kończy się niepowodzeniem. Następnie musisz wyzdrowieć z tego w ramach RTO i RCO. Czy firma rozumie ryzyko i czy masz plany na jego ograniczenie?

Jeśli firma nie zgadza się z tym, nie rób tego, to moja rada.

Ali Razeghi
źródło
2

Jeśli masz serwery działające w środowisku wirtualnym, możesz wykonać migawkę na klonie, a następnie zastosować aktualizację w miejscu i przetestować instancję, aby sprawdzić, czy aktualizacja zakończyła się powodzeniem. Jeśli to działa, możesz zastosować migawkę i sklonować serwer produkcyjny. Jeśli pójdzie źle, możesz usunąć migawkę i wrócić do obrazu przed aktualizacją, aby spróbować ponownie, lub usunąć klon i przejść do pełnej migracji.

Troja
źródło
1
Tylko jeśli pamięć jest również zwirtualizowana i stanowi część migawki. Jeśli pamięć jest bezpośrednio podłączona do maszyny wirtualnej, nie zostanie „cofnięta” po przywróceniu migawki ...
Remus Rusanu,
1

Ze względu na dużą inwestycję sprzętową musieliśmy zaktualizować tylko system operacyjny, zachowując aktualną wersję programu SQL Server (2012, 3 serwery, 22 instancje, ~ 300 baz danych). Bez skomplikowanych ustawień, takich jak tworzenie kopii lustrzanych itp.

Ten przykład nie pasuje dokładnie do pytania, ponieważ SQL Server nie jest aktualizowany. Myślę, że to nadal dobra odpowiedź, ponieważ pokazane kroki byłyby w rzeczywistości prostsze niż prawdziwa migracja w miejscu.

Omówienie: Podłączono dysk zewnętrzny w celu wykonywania pełnych kopii zapasowych głównie jako środek ostrożności. Tylko model i msdb zostaną faktycznie przywrócone z dysku zewnętrznego. Pliki ldf / mdf pozostawiono na miejscu w celu odłączenia / dołączenia. Niektóre konta lokalne zostały przywołane w bazach danych. Po ich ponownym utworzeniu w systemie operacyjnym ponownie utworzono odwołania w bazie danych (ponieważ identyfikatory SID mogą ulec zmianie).

Oto kroki, które działały dla nas:

1) Zwróć uwagę na ustawienia na poziomie serwera, które zostaną przywrócone w krokach 12 (Role serwera) i od 18 do 23.

2) Łata SQL Server 2012 do SP3 (wymagana spójność, jeśli chcemy przywrócić dowolne systemowe dbs).

3) Sprawdź, czy wersje pasują do każdej instancji. „Wybierz wersję @@”

4) Wygeneruj te 6 skryptów, uruchamiając ten skrypt. Redgate SQL Multiscript to ogromna oszczędność czasu, jeśli istnieje wiele wystąpień (Dostosuj narzędzia -> Opcje => Długość linii do maksimum (8192), a następnie użyj wyjścia tekstowego).

  • Utworzyć kopię zapasową
  • Przywracać
  • Odłączyć
  • Dołączać
  • Odtwórz loginy
  • Połącz ponownie użytkowników z loginami

    -- (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) Uruchom skrypt, aby wykonać kopię zapasową wszystkich baz danych, w tym systemu (master, msdb, model) na dysku zewnętrznym.

6) Uruchom skrypt, aby odłączyć wszystkie bazy danych

7) Dysk C zostanie ponownie sformatowany. Zachowaj LDF / MDF, jeśli NIE były w C.

8) Windows Server 2012 jest zainstalowany na C

9) Przenieś LDF / MDF dla oryginalnych plików systemowych na bok, jeśli nie były one na dysku C.

10) SQL Server 2012 zostanie ponownie zainstalowany i załatany do SP3 a. Ponownie utwórz systemowe konta użytkowników / grup

11) Wykonaj kopię zapasową DB systemu w nowej lokalizacji lub nazwie pliku (uważaj, aby nie zastąpić oryginałów!).

12) Uruchom ponownie fragment kodu ról. Coś jak:

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) Uruchom ponownie skrypt logowania (nic nie robi, jeśli loginy zostały przywrócone)

14) Zatrzymaj SQL AGENT.

(Moglibyśmy przywrócić Mistrza tutaj, stchórzyliśmy).

15) Załącz mdf / ldf za pomocą skryptu z góry. za. W przypadku niepowodzenia ręcznie przywróć z bak przy użyciu skryptu z góry.

16) Próba przywrócenia modelu

17) Upewnij się, że SQL Agent jest zatrzymany. Przywróć MSDB (link) a. Jeśli się nie powiedzie, musisz ponownie utworzyć zadania + plan konserwacji + konfiguracja poczty + operatorzy

18) Skrypt 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) Włącz brokera usługi, aby dopasował oryginalną wartość 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) Uruchom agenta SQL

21) Ustaw próg równoległości na pierwotną wartość

22) Dostosuj ustawienia bazy danych do ich oryginalnych wartości:

 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) Sprawdź własność pracy:

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

Gdyby wersja SQL Server również została zaktualizowana, nie sądzę, aby model i bazy danych msdb mogły zostać przywrócone, więc zadania zostałyby utracone z powodu https://support.microsoft.com/en-us/kb/264474

Czego brakuje:

  • Użytkownicy oryginalni w głównej bazie danych (rzadko?)
  • Role serwera
  • ?
Crokusek
źródło
0

Nie ma nic złego w żadnym z tych podejść per se - zrobiłem oba i oba wyniki są zazwyczaj dobre.

Jeśli występuje problem z podejściem do migracji, nie jest to techniczne: jest to lenistwo. Zbyt często uważam, że powodem, dla którego firma nie przeszła jeszcze w pełni do wersji xxxx, jest to, że wybrali migrację swingową i nigdy nie wykonali ciężkiej pracy, aby całkowicie się przenieść. Teraz mają dwa lub więcej zestawów serwerów zamiast jednego.

RowlandG
źródło