As atualizações no local do SQL Server são tão pouco recomendadas quanto costumavam ser?

78

Eu tenho trabalhado e desativado o SQL Server desde o SQL Server 6.5, o antigo conselho que ainda soa na minha cabeça é nunca fazer uma atualização no local.

Atualmente, estou atualizando meus sistemas DEV e TEST 2008 R2 para o SQL Server 2012 e preciso usar o mesmo hardware. O pensamento de não precisar restaurar minha configuração do Reporting Services é muito atraente e estou realmente contra o tempo da parede. Não há serviços de análise envolvidos ou algo incomum ou fora do padrão - apenas o mecanismo de banco de dados e os serviços de relatório estão instalados.

Alguém já teve problemas sérios com atualizações no local? Ou devo reavaliar minha posição sobre atualizações no local?

Mercadorias estragadas
fonte
Optei por fazer uma atualização local em um servidor com a instalação dos serviços de relatório. O único problema que me deparei foi tentar usar a ferramenta de exportação e importação no SSMS com o cliente nativo 11. A tentativa de transformação falhou com um erro sobre tipos de dados não reconhecidos. a solução alternativa que usei foi salvar o pacote e executá-lo no SQL Data Tools (substituição de BIDS), que funcionou bem. Eu acho que isso deve estar relacionado ao arquivo de configuração do SSIS 2008 que não está sendo substituído. Ocorreu-me mais tarde, você pode simplesmente ser capaz de mudar o cliente nativo de volta a 10.
DamagedGoods

Respostas:

92

Resposta muito curta - o local está ok. Você pode revisar sua configuração posteriormente e implementar as práticas recomendadas para o SQL Server 2012.

Uma resposta mais longa sobre atualizações / migrações do SQL Server

Portanto, isso é uma questão de opinião e não há uma resposta necessariamente errada ou correta, mas eu prefiro as atualizações do estilo de migração em vez do local por várias razões. Dito isto - alguns de meus clientes, por várias razões, não tiveram escolha a não ser fazer um local e, realmente, desde o SQL Server 2005, as atualizações locais não foram tão ruins quanto costumavam ser.

Por que prefiro uma migração a uma atualização no local

  • Reversão mais fácil - Se algo der errado, você poderá reverter simplesmente dizendo "cancelamos a atualização. Altere as cadeias de conexão para o servidor antigo enquanto resolvemos isso". Com um local, você está consertando ou está inoperante.
  • Atualizar hardware - o hardware muda rapidamente. Você pode facilmente ficar preso ao hardware adequado para sua empresa há 4 anos, mas não para hoje e nos próximos quatro anos com uma atualização no local. Você provavelmente terá que fazer uma migração em algum momento para o novo hardware.
  • Sinta-se melhor - claro ... Este é subjetivo, mas é bom saber que você está começando com uma nova instalação do sistema operacional, uma nova instalação SQL sem teias de aranha da pessoa que trabalha antes de você (ou você antes de saber o que sabia). hoje) que podem causar dores de cabeça no futuro.
  • Novo sistema operacional - Uma migração oferece a chance de começar com uma nova versão do sistema operacional, se você não estiver na melhor e mais recente hoje.
  • Você pode testá-lo - Você deseja obter um conjunto de linhas de base em uma nova máquina antes de instalar o SQL e utilizá-lo na nuvem com bancos de dados e uso? Você pode fazer isso agora.
  • Às vezes, é mais fácil se infiltrar nas práticas recomendadas - talvez a conta de serviço do SQL Server fosse um administrador local. Talvez os Administradores internos estejam na função de servidor SA. Talvez as coisas tenham sido meio que hackeadas para fazer funcionar antes. Você pode consertar tudo isso e começar do zero.
  • Ambiente de teste gratuito e sono extra - é um grande benefício ter um ambiente em que você possa trabalhar antes do dia de transição em que você viver esse novo ambiente. Fazer uma migração para um novo ambiente significa que você pode construí-lo durante o horário comercial, bem antes do dia de transição real e testá-lo de várias maneiras antes do tempo. Você pode executar testes de regressão completos em todos os aplicativos e sistemas por dias e ter uma grande tranqüilidade antes de executar o conjunto final de restaurações / anexos e substituir todos os aplicativos e acessar o novo ambiente.
  • Você não precisa fazer tudo de uma vez - Uma situação muito comum em que encontro um ambiente que está tentando se consolidar em apenas algumas instâncias. Talvez um por versão, talvez um por "camada" e versão. Muitos desses projetos têm cronogramas diferentes para vários aplicativos e bancos de dados, com base em testes, planos de projeto e pontualidade na certificação do fornecedor. Fazer a migração significa que você pode mover os bancos de dados prontos, quando estiverem prontos, e ainda manipular solicitações para os bancos de dados que não podem ser movidos por um motivo ou outro.

Mente-lhe Eu não estou dizendo que você tem de fazer isso como uma migração. O Local funciona e funciona bem se você não planeja comprar um novo hardware em seu orçamento e não pode fazer isso para esta atualização. O suporte no processo de atualização é muito melhor do que era nos 6,5 dias, para que você não se coloque em uma posição ruim fazendo isso.

Se você planeja executar no local para desenvolvimento / teste, mas deseja fazer uma migração para produção, considere fazer pelo menos uma migração antes da produção. Dessa forma, você pode elaborar sua lista de verificação com antecedência e lidar com possíveis problemas em que não estava pensando.

Anexar / desanexar vs. Backup / restauração para migrações

Se você decidir seguir a abordagem de migração, ainda há mais uma decisão sobre a qual você ainda pode debater e é assim que você move seu banco de dados para o novo ambiente. Você pode desanexar seu banco de dados do servidor antigo e anexá-lo ao novo ou fazer backup e restaurá-lo lá.

Eu prefiro backup / restauração. A maior vantagem que ouvi sobre desanexar / anexar é que ele economiza algum tempo. Para mim, o backup / restauração vence por alguns motivos:

  • Manter o antigo acessível - Isso permite que você ainda tenha um banco de dados acessível no servidor de origem. desanexar / anexar deve fazer o mesmo, mas serão necessárias algumas etapas e há espaço para erro humano ao desanexar / anexar que poderia complicar isso.
  • Você está garantindo que possui um backup - em vez de apenas tirar um banco de dados de uma desanexação e potencialmente esquecer uma etapa de backup, você garantiu que fez esse backup.
  • Erro humano - Se você excluir o arquivo errado, esqueça para onde está enviando algo ou atrapalhe suas etapas, corre o risco de mover os dados e os arquivos de log do seu banco de dados. Agora você pode atenuar isso copiando em vez de cortar (e, se desconectar, deve sair do hábito de recortar e colar), mas ainda pode estragar tudo. O SQL Server não está mais bloqueando esses arquivos e é muito fácil excluir um arquivo acidentalmente para que eu arrisque.
  • Não é realmente que mais lento - Fazer um backup e copiar é um tempo pouco mais, mas não é que muito do que eu estou disposto a pagar o risco extra para ele. De fato - usando o modelo de recuperação completa e os backups de log, você pode reduzir ainda mais o tempo de inatividade para os cortes, conforme descrito abaixo em "Como tornar a abordagem de migração mais rápida"

Se você decidir fazer o backup / restauração - isso significa que seu antigo banco de dados de origem ainda estará online. Eu gosto de colocar esse banco de dados offline depois de fazer o backup. Às vezes, dou um passo adiante e coloco toda a instância do SQL offline depois de criar scripts de segurança, trabalhos, servidor vinculado, certificados, configurações de correio do banco de dados e outras informações abrangentes da instância. Isso evita um problema durante o teste, em que alguém diz "Tudo parece ótimo!" apenas para perceber um ou dois dias depois que eles estavam conversando com o banco de dados antigo no servidor antigo. Colocar esses bancos de dados offline ou toda a instância offline permite evitar os falsos positivos e a bagunça que eles fazem.

Como tornar a abordagem de migração mais rápida

Você pode minimizar o tempo de inatividade necessário para a transição de um ambiente antigo para um novo para um ambiente de produção ocupado com pouco tempo de inatividade, utilizando o modelo de recuperação completa. Basicamente - prepare o ambiente para o qual você está migrando restaurando o backup completo mais recente, os backups diferenciais e os backups de log já realizados, especificando NORECOVERY- tudo o que você precisará fazer para o corte final é restaurar os backups de log que ainda não foram restaurados e o backup de log final que você deseja restaurar, especificando WITH RECOVERY. Dessa forma, para um banco de dados grande, a janela real de tempo de inatividade de transição pode ser drasticamente minimizada pagando pelo custo das restaurações completas, diferenciais e da maioria dos logs antes da janela de tempo de inatividade. Obrigado ao Tao por apontar isso nos comentários!

Como tornar a atualização no local mais segura

Algumas ações que você pode fazer para melhorar sua experiência e resultados ao escolher a abordagem no local.

  • Backup - Faça backups apropriados de todos os bancos de dados de usuários e sistemas do seu ambiente com antecedência e garanta que eles sejam bons (sou paranóico. Na verdade, eu os restauraria em algum lugar primeiro para realmente saber que eles são bons. Pode estar desperdiçando seu tempo. (Mas você pode agradecer a si mesmo no caso de um desastre). Script todas as informações de configuração sobre a instalação do SQL e OS nesse ambiente.
  • Teste bem as coisas antes de começar - Verifique se você possui um bom ambiente e bons bancos de dados. Você deve fazer coisas como examinar os logs de erros e executar o DBCC CHECKDB regularmente, mas antes de fazer uma atualização no local é um ótimo momento para começar. Corrija quaisquer problemas com antecedência.
  • Garantir a integridade do sistema operacional - não apenas verifique se o SQL está íntegro, mas também se o servidor está íntegro. Algum erro grave nos logs de eventos de erro do sistema ou do aplicativo? Como está o seu espaço livre?
  • Prepare-se para o pior - tive uma série de postagens no blog há algum tempo que partia da premissa de que, se você não está se preparando para o fracasso - está realmente se preparando para falhar ... Eu ainda acredito nisso. Portanto, pense sobre os problemas que você pode ter e lide com eles adequadamente com antecedência. Entre na mentalidade de "fracasso" e você pensará em coisas que você não teria de outra maneira.

A importância das listas de verificação de atualização ou migração

Se você decidir fazer uma atualização (no local ou na migração), considere seriamente criar uma lista de verificação e usá-la em cada ambiente. Você deve incluir várias coisas nesta lista de verificação, das quais não menos importante:

  1. No início - faça algumas coisas como executar uma atualização de teste, teste seus aplicativos no nível mais recente de Compatibilidade de Banco de Dados e considere executar uma ferramenta como o SQL Server Upgrade Advisor com antecedência para ver que tipo de tarefas você precisa concluir antes de executar o SQL Atualização ou migração do servidor.
  2. Pré-etapas - Limpeza, tarefas do sistema operacional, correções antecipadas, preparação de aplicativos para a atualização (desligamentos limpos, trabalho de cadeia de conexão), backups etc.
  3. Etapas de atualização / migração - Tudo o que você precisa fazer para que a atualização ou migração seja bem-sucedida e na ordem certa. Instalação, alteração (ou não, dependendo dos testes e da abordagem) do modo de compatibilidade muda para os bancos de dados, etc.
  4. Etapas de pós-migração / atualização - Vários testes, pós-nova versão ou novas opções de configuração do servidor, implementação de práticas recomendadas, alterações de segurança etc.
  5. Etapas de reversão - Ao longo do caminho, você deve ter etapas e marcos de reversão. Se você chegar até aqui e isso acontecer, o que você fará? O que são critérios "fazer uma reversão completa"? E como você faz essa reversão (alterações na cadeia de conexão reversa, alterações nas configurações, retorno à versão antiga, reinstalação se houver um local, aponte para o servidor antigo se houver uma migração etc.)

Depois, peça à pessoa que fará a atualização da produção que siga a lista de verificação em algum ambiente que não seja a produção - especialmente aquele que fecha se assemelha à produção, se possível ("Sul de prod", como eu digo ...) e anote quaisquer problemas ou pontos onde eles tiveram que desviar da lista de verificação ou improvisar devido à falta dela. Em seguida, junte as alterações e divirta-se com sua alteração na produção.

Não posso enfatizar demais a importância de testar completamente após a migração ou atualização e antes da sua migração o suficiente. Tomar uma decisão de reversão no meio de uma atualização deve ser fácil - especialmente durante uma migração. Se houver algo desconfortável, faça a reversão e descubra se você não pode solucionar problemas de maneira eficaz e confiável no calor da migração. Uma vez que você vive neste novo ambiente e os usuários se conectam, a reversão se torna uma tarefa difícil. Você não pode restaurar um banco de dados do SQL Server para uma versão anterior. Isso significa trabalho manual e migrações de dados. Eu sempre espero algumas semanas para matar o ambiente antigo, mas você deve fazer tudo o que puder para evitar a necessidade desse ambiente antigo, encontrando todos os seus problemas antes que seus usuários ativos toquem o novo ambiente. De preferência, antes mesmo de iniciar a atualização / migração.

Nota rápida sobre a migração / atualização do SQL Server Reporting Services A migração de uma instalação do SSRS não é uma tarefa hercúlea que muitos acham que é. Este artigo on-line do technet / books é realmente bastante útil . Uma das advertências mais importantes desse artigo é "Fazer backup das chaves de criptografia", especialmente se você tiver muitas informações confidenciais salvas, como endereços de email de destinatários de email de relatório agendado, informações de conexão para várias conexões etc. posso perguntar a um de meus clientes há algum tempo o quanto isso é importante. Eles sabem porque eu estraguei esse passo e passei bastante tempo modificando agendas de relatórios e permissões de cadeia de conexão.

Mike Walsh
fonte
14

Na minha experiência, o mesmo processo de tomada de decisão deve ser feito como antes. AFAIK, não houve nenhum 'trocador de mundo' com a instalação do SQL Server, no próprio produto MS SQL Server, e os possíveis problemas que você tem ao implantar software com milhões de linhas de código. Algo ruim pode acontecer e agora você está preso sem a opção 'ROLLBACK'.

No entanto, você tem outras alternativas em vigor. Você pode considerar fazer uma captura instantânea do sistema, restaurar em outro lugar, executar a atualização e ver o que acontece. Este teste deve proporcionar muito conforto, mas não garante absolutamente que não haverá problemas na caixa do produto. No entanto, esta é uma opção que não estava disponível no SQL 6.5 dias.

Eu apenas assumiria o pior cenário possível. Você faz uma atualização no local e ela falha miseravelmente. Você precisa se recuperar disso dentro do seu RTO e RCO. A empresa entende os riscos e você tem planos para mitigá-los?

Se o negócio não está bem com isso, então não faça isso seria o meu conselho.

Ali Razeghi
fonte
2

Se você tiver seus servidores em execução em um ambiente virtual, poderá executar uma captura instantânea em um clone e aplicar a atualização local e testar a instância para verificar se a atualização foi bem-sucedida. Se funcionar, você pode aplicar a captura instantânea e tornar o clone o servidor de produção. Se o resultado for ruim, você poderá excluir o instantâneo e voltar à imagem de pré-atualização para tentar novamente ou excluir o clone e fazer uma migração completa.

Troy
fonte
1
Somente se o armazenamento também for virtualizado e fizer parte do instantâneo. Se o armazenamento estiver diretamente conectado à VM, ele não será "revertido" quando o instantâneo for restaurado ...
Remus Rusanu
1

Devido a um grande investimento em hardware, fomos obrigados a atualizar apenas o SO, mantendo a versão atual do SQL Server (2012, 3 servidores, 22 instâncias, ~ 300 bancos de dados). Nenhuma configuração complexa, como espelhamento, etc.

Este exemplo não corresponde exatamente à pergunta, pois o SQL Server não está sendo atualizado. Eu acho que essa ainda é uma boa resposta, porque as etapas mostradas seriam realmente mais simples do que uma verdadeira migração no local.

Visão geral: Uma unidade externa foi conectada para fazer backups completos, principalmente como precaução. Somente o modelo e o msdb serão realmente restaurados a partir da unidade externa. Os ldf / mdf foram deixados no lugar para desanexar / anexar. Algumas contas locais foram referenciadas nos bancos de dados. Depois de recriadas no sistema operacional, as referências no banco de dados foram recriadas (pois os SIDs podem mudar).

Então, aqui estavam as etapas que funcionaram para nós:

1) Anote as configurações no nível do servidor que serão restauradas nas etapas 12 (Funções do servidor) e 18 a 23.

2) Aplique o patch do SQL Server 2012 ao SP3 (consistência necessária se desejarmos restaurar quaisquer dbs do sistema).

3) Verifique se as versões correspondem em cada instância. "Selecione @@ versão"

4) Gere esses 6 scripts executando este script. O Redgate SQL Multiscript economiza bastante tempo se houver muitas instâncias (ajuste Ferramentas -> Opções => Comprimento da linha ao máximo (8192) e use a saída de texto).

  • Cópia de segurança
  • Restaurar
  • Destacar
  • Anexar
  • Recriar logins
  • Vincular novamente os usuários aos logins

    -- (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) Execute o script para fazer backup de todos os bancos de dados, incluindo o sistema (mestre, msdb, modelo) na unidade externa.

6) Executar script para desanexar todos os bancos de dados

7) O drive C será reformatado. Preservar os LDF / MDF, se não estiverem em C.

8) Windows Server 2012 está instalado em C

9) Mova o LDF / MDF para os arquivos originais do sistema, se eles não estiverem na unidade C.

10) O SQL Server 2012 será reinstalado e corrigido no SP3 Recrie contas de usuário / grupo do sistema

11) Faça backup dos bancos de dados do sistema em um novo local ou nome de arquivo (cuidado para não sobrescrever os originais!).

12) Execute o snippet de recriação de funções. Algo como:

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) Execute recriar script de login (não faz nada se os logons foram restaurados)

14) Pare o SQL AGENT.

(Poderia restaurar o Mestre aqui, nós nos acovardamos).

15) Anexe mdf / ldf usando o script acima. uma. Se falhar, restaure manualmente do bak usando o script acima.

16) Tentativa de restauração do modelo

17) Verifique se o SQL Agent está parado. Restaurar MSDB (link) a. Se falhar, é necessário recriar trabalhos + plano de manutenção + configuração de correio + operadores

18) Script 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) Habilite o service broker para corresponder ao valor original 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) Inicie o SQL Agent

21) Defina o limite do paralelismo para o valor original

22) Ajuste as configurações do banco de dados aos seus valores originais:

 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) Verifique a propriedade do trabalho:

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 a versão do SQL Server também tivesse sido atualizada, não acredito que os bancos de dados modelo e msdb pudessem ter sido restaurados para que os trabalhos fossem perdidos devido a https://support.microsoft.com/en-us/kb/264474

O que está a faltar:

  • Usuários originais no banco de dados mestre (raro?)
  • Funções de servidor
  • ?
crokusek
fonte
0

Nada está errado com nenhuma das abordagens em si - eu fiz as duas coisas e ambos os resultados são normalmente bons.

Se houver um problema com a abordagem de migração, não é técnico: é preguiça. Muitas vezes, acho que o motivo pelo qual uma empresa ainda não foi totalmente para a versão xxxx é porque eles escolheram uma migração automática e nunca se deram ao trabalho de se mover completamente. Agora eles têm dois ou mais conjuntos de servidores em vez de um.

RowlandG
fonte