Dbatools #Parte4 Restore-DbaDatabase

Fala pessoal, continuando na nossa série sobre o Dbatools, hoje mostrarei um comando que utilizo bastante no meu dia a dia como DBA, como todo DBA, sempre temos que estar preparados para realizar uma operação de Restore, seja devido a um problema ou uma solicitação da equipe de desenvolvimento para atualizar os dados em homologação.

Se você ainda não leu os posts anteriores:

https://blogdojamal.wordpress.com/2018/08/24/dbatools-parte1/

https://blogdojamal.wordpress.com/2018/08/28/dbatools-parte2-export-dbascript/

https://blogdojamal.wordpress.com/2018/08/31/dbatools-parte3-test-dbalastbackup/

Uma operação de Restore parece ser relativamente simples na maioria dos casos, mas existem casos onde precisamos de muita atenção e esforço, por exemplo um restore ‘Point-in-time’ onde temos que voltar a base de dados para um ponto ou horário especifico e você tem 1000 arquivos de backups para serem restaurados, parece ser um serviço bem trabalhoso, e de fato é!

Vamos pensar no seguinte ambiente, eu tenho uma base de dados chamada ‘SQLDAYES’, para essa base tenho a seguinte política de backup:

  • Backup FULL semanal, realizado todos os domingos as 23:00h
  • Backup diferencial, realizado diariamente as 23:00h
  • Backup de log a cada 10 minutos

Tenho um problema no meu banco de dados sexta-feira as 18:00h, preciso restaurar esse banco de dados até as 17:50h para voltar ao ponto antes do problema.

A ordem correta para aplicarmos nosso restore seria:

  • Restaurar o FULL do último domingo
  • Restaurar o último DIFF, que seria o da quinta-feira as 23:00h
  • Restaurar todos os logs das 23:00h até as 17:50h

Ok, parece simples e serão poucos arquivos, mas as coisas podem ficar pior, você percebeu que não tinha uma rotina de teste de backup e quando foi verificar seu último FULL estava corrompido, sendo assim, a sequência acima não funcionará e você terá que seguir a seguinte ordem:

  • Restaurar o backup FULL do penúltimo domingo, ou seja, de 2 semanas atrás
  • Restaurar o último DIFF antes do FULL corrompido, que seria o DIFF do último sábado as 23:00h
  • Restaurar todos os logs de sábado das 23:00h até sexta-feira as 17:50h

Já imaginou a quantidade de arquivos? Agora parece um pouco mais trabalhoso não?!

Para simular essa operação irei criar um ambiente, porém não terá exatamente o cenário acima com backups de 2 semanas, mas uma vez que você tenha compreendido a sequência que iremos realizar, ficará fácil de entender.

Primeiramente, se você ainda não conhece essa fantástica solução tanto para backup quanto para manutenção de índices e estatísticas do Ola  Hallengren fica como seu dever de casa.

Quando configuramos a solução de backup do Ola Hallengren, temos por default a estrutura de pastas abaixo:

 

  • [Nome da instancia SQL Server]\[Nome da base de dados]\[Full]
  • [Nome da instancia SQL Server]\[Nome da base de dados]\[Diff]
  • [Nome da instancia SQL Server]\[Nome da base de dados]\[Log]

Nome do arquivo: [Nome da instancia SQL Server]_[Nome da base de dados]_[Data]_[Hora].

Para o meu ambiente eu tenho 4 backups FULL, primeiro as 22:43h do dia 03/09 e último as 08:00h do dia 04/09:

Screenshot_332

Tenho 7 backups diferenciais, primeiro as 22:44h do dia 03/09 e último as 09:00h do dia 04/09.

 

Screenshot_329

E 64 backups de log, primeiro as 22:45h do dia 03/09 e último as 09:10h do dia 04/09.

Screenshot_330

 

Eu preciso voltar meu banco de dados SQLDAYES até as 09:08h do dia 04/09, no cenário ideal eu precisaria restaurar apenas o último FULL das 08:00h, o último DIFF das 09:00h e o último log das 09:10h, para poder voltar especificamente as 09:08h, seria um ótimo cenário e com 3 comandos estaria pronto.

RESTORE DATABASE [Restore_SQLDAYES] FROM
DISK = N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\FULL\DESKTOP-A7S2JPV$SQLSERVER2016_SQLDAYES_FULL_20180904_080001.bak’ WITH FILE = 1, MOVE N’SQLDAYES’ TO N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Restore_SQLDAYES.mdf’, MOVE N’SQLDAYES_log’ TO N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Restore_SQLDAYES_log.ldf’,
NORECOVERY, NOUNLOAD, STATS = 10

RESTORE DATABASE [Restore_SQLDAYES] FROM DISK = N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DIFF\DESKTOP-A7S2JPV$SQLSERVER2016_SQLDAYES_DIFF_20180904_090001.bak’ WITH FILE = 1, MOVE N’SQLDAYES’ TO N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Restore_SQLDAYES.mdf’, MOVE N’SQLDAYES_log’ TO N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Restore_SQLDAYES_log.ldf’,
NORECOVERY, NOUNLOAD, STATS = 10

RESTORE LOG [Restore_SQLDAYES] FROM DISK = N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\LOG\DESKTOP-A7S2JPV$SQLSERVER2016_SQLDAYES_LOG_20180904_091000.trn’ WITH FILE = 1, MOVE N’SQLDAYES’ TO N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Restore_SQLDAYES.mdf’, MOVE N’SQLDAYES_log’ TO N’E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Restore_SQLDAYES_log.ldf’,
NOUNLOAD, STATS = 10, STOPAT = N’09/04/2018 09:08:00′

Screenshot_331

Comprovado, com apenas 3 comandos eu tenho minha base de dados restaurada até o ponto das 09:08h, mas ainda tivemos que decifrar quais backups precisaram ser restaurados.

Podemos já usar o Dbatools nesse caso, o comando Restore-DbaDatabase nos proporciona uma variedade de opções para restore de banco de dados, facilitando a sua vida, onde você pode restaurar centenas de arquivos de backup com apenas 1 comando sem se preocupar com a sequência correta dos arquivos, apenas especificando o ponto que deseja parar.

$RestoreTime = Get-Date(’09:08 04/09/2018′)

Restore-DbaDatabase -SqlInstance DESKTOP-A7S2JPV\SQLSERVER2016 -Path ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\’ -DestinationFilePrefix ‘Restore_’ -RestoredDatabaseNamePrefix ‘Restore_’ -MaintenanceSolutionBackup -DestinationLogDirectory ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\’ -DestinationDataDirectory ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\’ -RestoreTime $RestoreTime

Com o comando acima eu preciso apenas especificar a pasta onde estão meus backups, ele se encarrega em seguir a ordem correta dos arquivos. Ele irá restaurar todos os bancos de dados encontrados dentro das pastas, ou você pode especificar apenas o banco de dados desejado, para este caso, tenho apenas arquivos de um banco de dados então não irei especificar o nome, estou usando os seguintes parâmetros:

  • -SqlInstance: Instância de SQL Server
  • -Path: Caminho onde estão meus backups
  • -DestinationFilePrefix: Será adicionado um prefixo nos arquivos de dados e log durante o restore, isso facilita para fazer um restore com um nome diferente do banco original
  • -RestoredDatabaseNamePrefix: Mesmo caso acima, porém adiciona um prefixo no nome do banco de dados, para não sobrescrever o banco original
  • -MaintenanceSolutionBackup: Esse parâmetro é bem legal, indica que eu tenho uma rotina de backup como a Ola Hallengreen e entende que meus backups estão armazenados em uma estrutura de pastas como mostrado anteriormente, isso facilita o trabalho da rotina e consequentemente se torna mais rápido a checagem dos arquivos.
  • -DestinationLogDirectory: Diretório onde deseja salvar os arquivos de Log da base de dados restaurada
  • -DestinationDataDirectory: Diretório onde deseja salvar os arquivos de dados da base dados restaurada
  • -RestoreTime: Data e hora onde deseja parar o restore (Point-in-time)
  • -OutputScriptOnly: Apenas gerar os scripts

Screenshot_333

 

MAS, nem tudo são flores, o backup FULL das 08:00h e o das 04:00h estão corrompidos, e o desespero bate em sua porta.

 

Se eu não posso voltar o FULL das 08:00h e nem o das 04:00h, eu preciso do FULL das 00:00h, logo eu posso voltar apenas o DIFF das 03:00h, pois os demais arquivos acima das 04:00h são baseados no FULL das 04:00h e não serão aplicáveis,  e posteriormente aplicar os logs das 03:00h até as 09:10h, no meu caso são apenas 38 arquivos, mas pense no cenário que mencionei lá em cima, com backup FULL 1 vez por semana, 1 DIFF diário e LOG a cada 10 minutos, com os 2 últimos FULL corrompidos, será um trabalho árduo, em casos reais já cheguei a restaurar mais de 1000 backups de Log (deixe nos comentários o seu record).

Com o comando Restore-DbaDatabase, podemos voltar toda essa cadeia de backups com apenas 1 comando.

$RestoreTime = Get-Date(’09:08 04/09/2018′)

Restore-DbaDatabase -SqlInstance DESKTOP-A7S2JPV\SQLSERVER2016 -Path ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\’ -DestinationFilePrefix ‘Restore_’ -RestoredDatabaseNamePrefix ‘Restore_’ -MaintenanceSolutionBackup -DestinationLogDirectory ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\’ -DestinationDataDirectory ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\’ -RestoreTime $RestoreTime   -OutputScriptOnly | Out-File ‘C:\Temp\Restore.sql’

Adicionei o parâmetro -OutputScriptOnly para fazer a exportação do script ao invés de executar, após o Pipeline Out-File ‘C:\Temp\Restore.sql’, exportando o script para um arquivo com extensão .sql.

Screenshot_334

Screenshot_335

Pronto, tenho o script do comando completo de Restore para voltar meu banco de dados até as 09:08h, ou posso executa-lo direto conforme resultado abaixo:

Screenshot_336

Banco de dados restaurado com sucesso, registro do último Log aplicado, onde informa que a opção NoRecovery foi ‘Falsa’, isso indica que deixou nosso banco de dados operacional e pronto para uso.

Posso utilizar para automatizar uma rotina de restore que ocorre com frequência, como solicitações de desenvolvedores.

Get-DbaBackupHistory -SqlServer DESKTOP-A7S2JPV\SQLSERVER2016 -Databases SQLDAYES | Restore-DbaDatabase -SqlServer DESKTOP-A7S2JPV\SQLSERVER2016_02 -useDestinationDefaultDirectories -IgnoreLogBackup -WithReplace

O comando acima está utilizando o Get-DbaBackupHistory para ler todo o histórico de backups do banco de dados SQLDAYES na instância SQLSERVER2016 e passando via Pipeline para o comando Restore-DbaDatabase que irá utilizar essa informações para restaurar o banco de dados SQLDAYES na instância SQLSERVER2016_02.

Resultado do comando Get-DbaBackupHistory:

Screenshot_337

Resultado do comando completo:

Screenshot_338

Você pode utilizar o trecho abaixo para exportar o resultado em um arquivo .txt:

| Out-File ‘C:\temp\RestoreResult.txt’

Screenshot_344

 

DICA bônus: Uma dica muito legal de PowerShell é a utilização do parâmetro -WHATIF o famoso “Mas e se”, muito útil para testar comandos complexos ou duvidosos, quando informado o parâmetro WHATIF ele apenas testa o comando e retorna o que acontecerá quando esse comando for executado.

Vamos supor que eu gostaria de apagar os arquivos de uma pasta que tenha ‘Log’ no seu nome, pela imagem abaixo eu tenho 2 arquivos.

Screenshot_342

Desenvolvi o comando abaixo, mas estou um pouco em dúvida quanto a execução.

Get-ChildItem ‘E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA’ | Where-Object Name -Like ‘*log*’ | Remove-Item

Então eu posso executar o comando Remove-Item com o parâmetro -WhatIf:

Screenshot_343

What if: Performing the operation “Remove File” on target “E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\Logs.txt”.
What if: Performing the operation “Remove File” on target “E:\DESKTOP-A7S2JPV$SQLSERVER2016\SQLDAYES\DATA\LogSQL.txt”.

O resultado é a descrição do que aconteceria, mas o meu comando não foi executado.

 

Reginaldo, é só isso? O tema backup é um assunto complexo, perceba que eu abordei de forma simplista e focando em como recuperar os backups e na utilização do comando, subentendendo que você já conheça as diferenças dos recovery model SIMPLE, BULKED LOGGED e FULL, também entenda as diferenças entre backup FULL, Diferencial e Log, deixarei algumas referências para você ficar mais situado sobre esse assunto. O objetivo principal é mostrar comandos que eu utilizo no meu dia a dia e que a partir dessas demonstrações vocês consigam extrair ideias levando para o mundo ao seu redor, o comando Restore-DbaDatabase é completamente parametrizável e dinâmico, pode ser adequado em uma rotina de restore que você já tenha hoje, assim como te ajudar em um momento difícil onde você precise restaurar centenas de arquivos, não se limite aos exemplos apresentados em nenhum artigo, sempre procure ir além levando os testes para o seu mundo, dessa forma você conseguirá absorver muito mais conhecimento.

Se você tiver alguma dúvida referente a backup\restore, fique à vontade de enviar um e-mail ou deixar seu comentário.

O blog do Edvaldo Castro é uma ótima referência para estudos e quando o assunto é Backup ele é fera:

https://edvaldocastro.com/backup-full-diario/

https://edvaldocastro.com/politicabkp/

https://edvaldocastro.com/backup01/

Modelos de recuperação:

https://docs.microsoft.com/pt-br/sql/relational-databases/backup-restore/recovery-models-sql-server?view=sql-server-2017

 

Até a próxima, abraços!

Reginaldo Silva

2 comentários sobre “Dbatools #Parte4 Restore-DbaDatabase

  1. Opa, queria dar os parabéns pelo post, e dizer que este recurso do dbatools é muito legal. As vezes pensamos que situações como a de ter de restaurar um grande número de logs são raras de acontecer, mas acontecem, sim, e devemos estar preparados para isto!

    Curtir

  2. Caro Reginaldo,

    Ficou bem legal a série DBATools. Tb estou usando aqui no meu trabalho.
    A minha unica duvida seria como fazer acessos a uma Database en outro dominio.

    Exemple: Dominio1/user é igual com a mesma senha do dominio 2. A grande diferenca seria o nome do dominio. Estou com esse problema. Ja teve caso assim? Como faria para acessar?

    PS H:\> Get-DbaDatabase -SqlInstance Nome_da_Instancia
    WARNING: [09:21:27][Get-DbaDatabase] Failure | Can’t connect to Nome_da_Instancia: System.ComponentModel.Win32Exception
    (0x80004005): The user name or password is incorrect

    Abracos,
    Bruno

    Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s