Gli aggiornamenti sul posto di SQL Server sono sconsigliati come una volta?


78

Lavoro con il server SQL acceso e spento da SQL Server 6.5, il vecchio consiglio che mi risuona ancora nella testa non è mai stato quello di fare un aggiornamento sul posto.

Attualmente sto aggiornando i miei sistemi DEV e TEST R2 R2 a SQL Server 2012 e devo utilizzare lo stesso hardware. Il pensiero di non dover ripristinare la configurazione dei miei servizi di reportistica è molto interessante e sono davvero contro il tempo del muro. Non sono coinvolti servizi di analisi o qualcosa di insolito o non standard: sono installati solo il motore di database e i servizi di reportistica.

Qualcuno ha riscontrato seri problemi con gli aggiornamenti sul posto? O dovrei rivalutare la mia posizione sugli aggiornamenti sul posto?


Ho optato per un aggiornamento sul posto su 1 server con l'installazione dei servizi di reportistica. L'unico problema che ho riscontrato è stato il tentativo di utilizzare lo strumento di importazione / esportazione in SSMS con client nativo 11. Il tentativo di trasformazione non è riuscito con un errore relativo a tipi di dati non riconosciuti. la soluzione che ho usato è stata quella di salvare il pacchetto ed eseguirlo in SQL Data Tools (sostituzione BIDS) che ha funzionato bene. Penso che questo abbia a che fare con il file di configurazione per SSIS 2008 che non viene sovrascritto. Mi è successo dopo, potresti semplicemente essere in grado di ripristinare il client nativo in 10.
DamagedGoods

Risposte:


92

Risposta davvero breve - Sul posto va bene. Successivamente è possibile rivedere la configurazione e implementare le procedure consigliate per SQL Server 2012.

Una risposta più lunga su aggiornamenti / migrazioni di SQL Server

Quindi questa è un'opinione e non c'è una risposta necessariamente sbagliata o giusta, ma preferisco gli aggiornamenti dello stile di migrazione sul posto per molte ragioni. Detto questo, alcuni dei miei clienti per varie ragioni non hanno avuto altra scelta che fare un intervento sul posto e proprio da SQL Server 2005, gli aggiornamenti sul posto non sono stati così male come una volta.

Perché preferisco una migrazione a un aggiornamento sul posto

  • Rollback più semplice - Se qualcosa va storto, è possibile eseguire il rollback semplicemente dicendo "abbiamo interrotto l'aggiornamento. Si prega di cambiare le stringhe di connessione al vecchio server mentre lo risolviamo". Con un posto sul posto lo stai riparando o sei giù.
  • Aggiorna hardware : l'hardware cambia rapidamente. Puoi facilmente rimanere bloccato sull'hardware che era giusto per la tua azienda 4 anni fa, ma non è adatto per oggi e per i prossimi quattro anni con un aggiornamento sul posto. Probabilmente dovrai comunque eseguire una migrazione ad un certo punto per il nuovo hardware.
  • Sentiti meglio - Sicuro ... Questo è soggettivo, ma è bello sapere che stai iniziando con una nuova installazione del sistema operativo, una nuova installazione SQL senza ragnatele dalla persona sul posto di lavoro (o tu prima di sapere cosa sapevi) oggi) che potrebbe causare mal di testa in futuro.
  • Nuovo sistema operativo : una migrazione ti dà la possibilità di iniziare con una nuova versione del sistema operativo se non sei aggiornato e aggiornato oggi.
  • Puoi provarlo - Hai mai desiderato ottenere un set di linee di base su un nuovo computer prima di installare SQL e cloud con database e utilizzo? Puoi farlo ora.
  • A volte è più semplice intrufolarsi nelle migliori pratiche : forse l'account del servizio SQL Server era un amministratore locale. Forse gli amministratori integrati hanno il ruolo di server SA. Forse le cose sono state un po 'messe insieme per farle funzionare prima. Puoi risolvere tutto e ricominciare da capo.
  • Ambiente di test gratuito e sonno extra - È un grande vantaggio avere un ambiente in cui lavorare in anticipo rispetto al giorno del ritaglio effettivo quando si fa vivere questo nuovo ambiente. Effettuare una migrazione verso un nuovo ambiente significa che è possibile crearlo durante l'orario di lavoro, con largo anticipo rispetto al giorno del ritaglio effettivo e testarlo in molti modi in anticipo. È possibile eseguire test di regressione completi su tutte le applicazioni e i sistemi per giorni e avere una grande tranquillità prima di eseguire effettivamente il set finale di ripristini / allegati e tagliare tutte le applicazioni e accedere al nuovo ambiente.
  • Non devi farlo tutto in una volta - Una situazione molto comune in cui mi imbatto è un ambiente che sta cercando di consolidare in pochi casi. Forse uno per versione, forse uno per "livello" e versione. Molti di questi progetti hanno tempistiche diverse per varie applicazioni e database basati su test, piani di progetto e tempestività della certificazione del fornitore. Effettuare la migrazione significa che è possibile spostare quei database che sono pronti, quando sono pronti e gestire comunque le richieste per quei database che non possono essere spostati per un motivo o per l'altro.

Intendiamoci Non sto dicendo che si deve fare questo come una migrazione. Sul posto funziona e funziona bene se non hai intenzione di acquistare nuovo hardware nel tuo budget e non puoi farlo per questo aggiornamento. Il supporto nel processo di aggiornamento è molto meglio di quanto non fosse nei 6,5 giorni, quindi non ti stai mettendo in una brutta posizione.

Se hai intenzione di fare sul posto per dev / test ma vuoi fare una migrazione per la produzione, potresti considerare di effettuare almeno una migrazione prima della produzione. In questo modo puoi elaborare la tua lista di controllo in anticipo e affrontare qualsiasi potenziale problema a cui non stavi pensando.

Allega / Scollega vs. Backup / Ripristina per migrazioni

Se decidi di seguire l'approccio alla migrazione, c'è ancora un'altra decisione su cui potresti ancora avere un dibattito ed è così che sposti il ​​tuo database nel nuovo ambiente. È possibile scollegare il database dal vecchio server e collegarlo al nuovo oppure eseguirne il backup e ripristinarlo lì.

Preferisco il backup / ripristino. Il più grande vantaggio che sento di staccare / allegare è che fa risparmiare un po 'di tempo. Per me il backup / ripristino vince per alcuni motivi:

  • Mantieni accessibile il vecchio - Ciò ti consente di avere ancora un database accessibile sul server di origine. staccare / attaccare dovrebbe fare lo stesso, ma richiederà alcuni passaggi e c'è spazio per l'errore umano con staccare / attaccare che potrebbe complicare questo.
  • Stai garantendo di avere un backup - Invece di prendere semplicemente un database da un distacco e potenzialmente dimenticare un passaggio di backup, ti sei assicurato di aver effettuato quel backup.
  • Errore umano : se si elimina il file errato, si dimentica dove si sta inviando qualcosa o si sbagliano i propri passi, si rischia molto spostando i dati e i file di registro per il proprio database. Ora puoi mitigarlo copiando invece di tagliare (e se ti stacchi, dovresti uscire dall'abitudine di tagliare e incollare) ma potresti sbagliare. SQL Server non blocca più questi file ed è semplicemente troppo facile eliminare un file accidentalmente per me rischiarlo.
  • Non è poi così lento : fare un backup e copiarlo richiede un po 'più di tempo, ma non è così tanto che sono disposto a pagare il rischio extra per questo. In effetti, utilizzando il modello di recupero completo e i backup dei log, è possibile ridurre i tempi di inattività anche per le interruzioni come descritto di seguito in "Come rendere più rapido l'approccio alla migrazione"

Se decidi di eseguire il backup / ripristino, significa che il tuo vecchio database di origine sarà ancora online. Mi piace portare quel database offline dopo aver eseguito il backup. A volte faccio un passo avanti e porto offline l'intera istanza di SQL dopo aver scritto la sicurezza, i lavori, il server collegato, i certificati, le impostazioni della posta del database e altre informazioni a livello di istanza. Questo evita un problema durante i test in cui qualcuno dice "Tutto sembra fantastico!" solo per rendersi conto un giorno o due dopo di aver parlato con il vecchio database sul vecchio server. Portare offline quei database o l'intera istanza offline consente di prevenire quei falsi positivi e il disordine che creano.

Come rendere più rapido l'approccio alla migrazione

È possibile ridurre al minimo i tempi di inattività richiesti per il passaggio da un ambiente vecchio a un nuovo per un ambiente di produzione occupato con tempi di inattività ridotti utilizzando il modello di recupero completo. Fondamentalmente - metti in scena l'ambiente verso cui stai eseguendo la migrazione ripristinando l'ultimo backup completo, eventuali backup differenziali e tutti i backup dei log già eseguiti specificando NORECOVERY- quindi tutto ciò che dovrai fare per il taglio finale è ripristinare i backup dei log che non sono stati ancora ripristinati e il backup del registro finale che si desidera ripristinare specificando WITH RECOVERY. In questo modo, per un database di grandi dimensioni, è possibile ridurre drasticamente la finestra dei tempi di inattività del cutover pagando il costo del ripristino completo, differenziale e della maggior parte dei log prima della finestra di inattività. Grazie a Tao per averlo sottolineato nei commenti!

Come rendere più sicuro l'aggiornamento sul posto

Alcune cose che puoi fare per migliorare la tua esperienza e i risultati quando scegli l'approccio sul posto.

  • Backup : esegui in anticipo i backup appropriati di tutti i database di utenti e di sistema del tuo ambiente e assicurati che siano buoni (sono paranoico .. In realtà li ripristinerei da qualche parte prima di sapere davvero che sono buoni .. Potrebbe farti perdere tempo. Ma potresti ringraziarti in caso di disastro). Scrivere tutte le informazioni di configurazione sull'installazione di SQL e OS in quell'ambiente.
  • Prova le cose molto prima di iniziare - Verifica di avere un buon ambiente e buoni database. Dovresti fare cose come guardare i log degli errori ed eseguire DBCC CHECKDB su base regolare, ma prima di fare un aggiornamento sul posto è un ottimo momento per iniziare. Risolvi eventuali problemi in anticipo.
  • Garantire l'integrità del sistema operativo : non solo assicurarsi che SQL sia integro, ma che il server sia integro. Eventuali errori nodosi nel registro degli eventi di errore del sistema o dell'applicazione? Com'è il tuo spazio libero?
  • Preparati al peggio - ho avuto una serie di post sul blog qualche tempo fa che si basava sul presupposto che se non ti stai preparando per il fallimento - in realtà ti stai preparando a fallire .. Ci credo ancora. Quindi pensa ai problemi che potresti avere e affrontali di conseguenza in anticipo. Mettiti nella mentalità del "fallimento" e penserai a cose che altrimenti non avresti.

L'importanza delle liste di controllo per l'aggiornamento o la migrazione

Se decidi di effettuare un aggiornamento (sia in atto che in migrazione), dovresti prendere seriamente in considerazione la creazione di un elenco di controllo e l'utilizzo di questo elenco di controllo in ciascun ambiente. Dovresti includere un sacco di cose in questo elenco di controllo, non ultimo dei quali:

  1. All'inizio : eseguire alcune operazioni come eseguire un aggiornamento di prova, testare le applicazioni all'ultimo livello di compatibilità del database e considerare di eseguire uno strumento come SQL Server Upgrade Advisor in anticipo per vedere che tipo di attività è necessario completare prima di eseguire l'SQL Aggiornamento o migrazione del server.
  2. Passaggi preliminari : pulizia, attività del sistema operativo, patch in anticipo, preparazione delle applicazioni per l'aggiornamento (arresti puliti, funzionamento della stringa di connessione), backup , ecc.
  3. Passaggi di aggiornamento / migrazione : tutto ciò che è necessario fare affinché l'aggiornamento o la migrazione abbia esito positivo e nel giusto ordine. Installazione, modifica (o non modifica a seconda del test e dell'approccio) modifica della modalità di compatibilità nei database, ecc.
  4. Passaggi successivi alla migrazione / aggiornamento : vari test, pubblicazione di nuove versioni o nuove opzioni di configurazione del server, implementazione delle migliori pratiche, modifiche alla sicurezza, ecc.
  5. Passaggi di rollback : lungo tutto il percorso dovresti avere passaggi di rollback e pietre miliari. Se arrivi così lontano e questo succede, cosa farai? Quali sono i criteri "esegui un rollback completo"? E come eseguire il rollback (modifica della stringa di connessione inversa, modifica delle impostazioni, ritorno alla versione precedente, reinstallazione se presente, reindirizzamento al vecchio server in caso di migrazione, ecc.)

E poi fai in modo che la persona che eseguirà l'aggiornamento della produzione segua la lista di controllo in un ambiente diverso dalla produzione - in particolare uno che chiude assomiglia alla produzione, se possibile ("South of prod", come dico ...) e nota eventuali problemi o punti dove dovevano deviare dalla lista di controllo o improvvisare a causa di una mancanza nella lista di controllo. Quindi unisci le modifiche e divertiti con il tuo cambio di produzione.

Non posso sottolineare troppo l'importanza di testare accuratamente dopo la migrazione o l'aggiornamento e prima della migrazione abbastanza. Prendere una decisione di rollback nel mezzo di un aggiornamento dovrebbe essere facile, specialmente durante una migrazione. Se c'è qualcosa di scomodo, esegui il rollback e scoprilo se non riesci a risolverlo in modo efficace e affidabile nel calore della migrazione. Una volta che sei vivo su questo nuovo ambiente e gli utenti si connettono, il rollback diventa un compito difficile. Non è possibile ripristinare un database di SQL Server su una versione precedente. Ciò significa lavoro manuale e migrazione dei dati. Aspetto sempre un paio di settimane per uccidere il vecchio ambiente, ma dovresti fare tutto il possibile per evitare di aver bisogno di quel vecchio ambiente, trovando tutti i tuoi problemi prima che gli utenti live possano toccare il nuovo ambiente. Preferibilmente prima ancora di iniziare l'aggiornamento / migrazione.

Nota rapida sulla migrazione / aggiornamento di SQL Server Reporting Services La migrazione di un'installazione SSRS non è un'attività abbastanza erculea che molti pensano che sia. Questo articolo online di technet / books è in realtà abbastanza utile . Una delle ammonizioni più importanti in quell'articolo è "Esegui il backup delle chiavi di crittografia", specialmente se hai molte informazioni sensibili salvate come indirizzi di posta elettronica dei destinatari del rapporto programmato, informazioni sulla connessione per una moltitudine di connessioni, ecc. posso chiedere a uno dei miei clienti da un po 'di tempo quanto sia importante. Lo sanno perché ho sbagliato quel passaggio e ho trascorso molto tempo a modificare le pianificazioni dei report e le autorizzazioni della stringa di connessione.


14

Nella mia esperienza, lo stesso processo decisionale dovrebbe essere preso come prima. AFAIK non ci sono stati "cambiamenti nel mondo" con l'installazione di SQL Server, all'interno del prodotto MS SQL Server in sé, e i potenziali problemi che si verificano durante l'implementazione del software con milioni di righe di codice. Potrebbe succedere qualcosa di brutto e ora sei bloccato senza l'opzione "ROLLBACK".

Tuttavia, esistono altre alternative. Potresti prendere in considerazione la possibilità di creare un'istantanea del sistema, ripristinare altrove, eseguire l'aggiornamento e vedere cosa succede. Questo test dovrebbe darti un sacco di conforto, ma non garantisce assolutamente che non sorgano problemi sulla scatola del pungolo. Tuttavia, questa è un'opzione che non era disponibile in SQL 6.5 giorni.

Vorrei solo ipotizzare lo scenario peggiore. Fai un aggiornamento sul posto e fallisce miseramente. È quindi necessario recuperare da questo all'interno di RTO e RCO. L'azienda comprende i rischi e ha in atto piani per mitigarli?

Se il business non va bene con questo, allora non farlo sarebbe il mio consiglio.


2

Se i server sono in esecuzione in un ambiente virtuale, è possibile eseguire un'istantanea su un clone e quindi applicare l'aggiornamento sul posto e testare l'istanza per verificare che l'aggiornamento abbia avuto esito positivo. Se funziona, è possibile applicare l'istantanea e rendere il clone il server di produzione. Se va male, è possibile eliminare l'istantanea e tornare all'immagine di pre-aggiornamento per riprovare, oppure eliminare il clone e una migrazione completa.


1
Solo se l'archiviazione è anche virtualizzata e parte dell'istantanea. Se l'archiviazione è direttamente collegata alla VM non verrà "ripristinata" quando viene ripristinata l'istantanea ...
Remus Rusanu,

1

A causa di un grande investimento hardware, ci è stato richiesto di aggiornare solo il sistema operativo mantenendo l'attuale versione di SQL Server (2012, 3 server, 22 istanze, ~ 300 database). Nessuna configurazione complessa come il mirroring, ecc.

Questo esempio non corrisponde esattamente alla domanda poiché SQL Server non viene aggiornato. Penso che questa sia ancora una buona risposta perché i passaggi mostrati sarebbero in realtà più semplici di una vera migrazione sul posto.

Panoramica: è stata collegata un'unità esterna per eseguire backup completi principalmente come precauzione. Solo il modello e msdb verranno effettivamente ripristinati dall'unità esterna. I file ldf / mdf sono stati lasciati in posizione per il distacco / collegamento. Alcuni account locali sono stati referenziati all'interno dei DB. Dopo che sono stati ricreati nel sistema operativo, sono stati ricreati i riferimenti all'interno del DB (poiché i SID possono cambiare).

Quindi ecco i passaggi che hanno funzionato per noi:

1) Prendere nota delle impostazioni a livello di server che verranno ripristinate nei passaggi 12 (Ruoli server) e 18 a 23.

2) Patch SQL Server 2012 a SP3 (coerenza richiesta se vogliamo ripristinare qualsiasi dbs di sistema).

3) Verificare che le versioni corrispondano su ciascuna istanza. "Seleziona la versione @@"

4) Genera questi 6 script eseguendo questo script. Redgate SQL Multiscript è un enorme risparmio di tempo se ci sono molte istanze (Regola gli strumenti -> Opzioni => Lunghezza linea al massimo (8192) e quindi utilizza l'output di testo).

  • di riserva
  • Ristabilire
  • distaccare
  • allegare
  • Ricrea gli accessi
  • Ricollegare gli utenti agli accessi

    -- (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) Eseguire lo script per eseguire il backup di tutti i DB incluso il sistema (master, msdb, modello) sull'unità esterna.

6) Eseguire lo script per scollegare tutti i DB

7) C L'unità verrà riformattata. Conservare i LDF / MDF se NON fossero su C.

8) Windows Server 2012 è installato su C

9) Spostare LDF / MDF per i file di sistema originali di mezzo se non si trovavano sull'unità C.

10) SQL Server 2012 verrà reinstallato e patchato con SP3 a. Ricreare account utente / gruppo di sistema

11) Eseguire il backup dei DB di sistema in una NUOVA posizione o nome file (fare attenzione a non sovrascrivere gli originali!).

12) Esegui ricreare snippet di ruoli. Qualcosa di simile a:

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) Esegui ricreare lo script di accesso (non fa nulla se gli accessi sono stati ripristinati)

14) Arrestare SQL AGENT.

(Potrebbe ripristinare il Maestro qui, ci siamo messi a ridere).

15) Allega mdf / ldf usando lo script dall'alto. un. In caso contrario, ripristinare manualmente da bak utilizzando lo script dall'alto.

16) Tentativo di ripristino del modello

17) Assicurarsi che SQL Agent sia arrestato. Ripristina MSDB (collegamento) a. Se fallisce, è necessario ricreare lavori + piano di manutenzione + configurazione della posta + operatori

18) Apri script utente per accedere ...

    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) Abilitare il broker di servizi affinché corrisponda al valore SELEZIONA nome SELEZIONA, is_broker_enabled DA database sys.d;

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

20) Avviare SQL Agent

21) Impostare la soglia di parallelismo sul valore originale

22) Regola le impostazioni del database sui loro valori originali:

 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) Verifica la proprietà del lavoro:

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

Se anche la versione di SQL Server fosse stata aggiornata, non credo che i database modello e msdb avrebbero potuto essere ripristinati, quindi i lavori sarebbero andati persi a causa di https://support.microsoft.com/en-us/kb/264474

Cosa manca:

  • Utenti originali nel database principale (raro?)
  • Ruoli del server
  • ?

0

Nulla di sbagliato in entrambi gli approcci di per sé - ho fatto entrambi ed entrambi i risultati sono generalmente buoni.

Se c'è un problema con l'approccio alla migrazione, non è tecnico: è pigrizia. Troppo spesso trovo che la ragione per cui un'azienda non è ancora passata completamente alla versione xxxx è perché ha scelto una migrazione swing e non ha mai fatto il duro lavoro per spostarsi completamente. Ora hanno due o più set di server anziché uno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.