Introdução
Existem várias situações que garantem a movimentação de arquivos de banco de dados ou arquivos de log de transações de um volume para outro no mesmo servidor. Estes podem incluir:
- A necessidade de formatar o volume assumindo que ele não foi formatado corretamente quando o SQL Server foi instalado . Lembre-se de que, ao instalar o SQL Server, é recomendável que o tamanho da unidade de alocação de 64 K seja usado para formatar os volumes. Se isso não for feito no momento da instalação e precisar ser feito posteriormente, obviamente será necessário preservar um backup do banco de dados primeiro ou criar um novo volume devidamente formatado e mover o banco de dados para esse novo volume.
- A necessidade de usar um novo volume supondo que os limites tenham sido atingidos para o armazenamento subjacente . Um bom exemplo seria o limite de 2 TB de um VMware Data Store. Este é o caso do VSphere 5.0. Versões superiores do VSphere têm limites muito maiores.
- A necessidade de melhorar o desempenho gerenciando o IO . Mais uma razão pela qual você pode querer mover os arquivos de dados é o desempenho. Há casos em que um banco de dados é criado com vários arquivos de dados todos em um disco até que se torne óbvio, à medida que o banco de dados cresce, que você criou uma “região quente” na camada de armazenamento. Uma solução seria criar novos arquivos de dados e reconstruir índices clusterizados, outra seria mover arquivos de dados.
Cenário Um:Movendo Bancos de Dados de Usuários
As etapas envolvidas na movimentação de um banco de dados de usuário envolvem o seguinte:
- Coloque o banco de dados offline
- Atualize o catálogo do sistema com o novo local
- Copie o arquivo de dados fisicamente para o novo local
- Coloque o banco de dados online
A Listagem 1 mostra os comandos executados para realizar essas etapas.
Listagem de 1 arquivos de dados móveis
-- 1. Run the following statement to check the current location of files. SELECT name, physical_name AS CurrentLocation, state_desc FROM sys.master_files WHERE database_id = DB_ID(N'BranchDB'); -- 2. Take the database offline. ALTER DATABASE BranchDB SET OFFLINE; -- 3. Move the file or files to the new location (at OS level). -- 4. For each file moved, run the following statement. ALTER DATABASE BranchDB MODIFY FILE ( NAME = WWI_UserData, FILENAME = 'N:\MSSQL\Data\WWI_UserDataNew.ndf' ); -- 5. Run the following statement. ALTER DATABASE BranchDB SET ONLINE; -- 6. Verify the file change by running the following query. SELECT name, physical_name AS CurrentLocation, state_desc FROM sys.master_files WHERE database_id = DB_ID(N'BranchDB');
É importante observar que, ao colocar um banco de dados offline, o número de sessões ativas pode atrasar o processo. Agendar um tempo de inatividade para executar essa tarefa seria uma boa ideia. Durante esse tempo de inatividade, o proprietário do aplicativo deve interromper a conexão dos serviços do aplicativo ao banco de dados antes que o DBA tente colocar o banco de dados offline. Há casos em que não é tão conveniente colocar o banco de dados offline, então desligar a instância seria a melhor opção. Nesse caso, a abordagem seria um pouco diferente:
- Atualize o catálogo do sistema com o novo local
- Desligar a instância
- Copie o arquivo de dados desejado fisicamente para o novo local
- Iniciar a instância
Em ambas as abordagens, o conceito é o mesmo:envolve atualizar o catálogo do sistema no banco de dados mestre e, em seguida, realocar fisicamente o arquivo de dados desejado. Em ambos os casos, o arquivo de dados deve ser fechado de forma limpa. Vamos dar uma olhada nas etapas envolvidas na primeira abordagem.
Fig. 1 Verifique a localização dos arquivos de dados
O primeiro passo seria verificar o estado da coisa para começar. O procedimento para definir o banco de dados offline e modificar o catálogo do sistema.
Fig. 2 Definir banco de dados offline e modificar catálogo
Conforme visto na Fig. 3, uma vez que atualizamos o catálogo, consultar sys.master_files nos informa o novo local em que o banco de dados mestre espera que o arquivo de dados esteja, independentemente de termos movido fisicamente o arquivo ou não. Na Fig. 4, também vemos que não é possível colocar o banco de dados online sem primeiro mover o arquivo para o novo local fisicamente (e renomear o arquivo para corresponder ao novo nome especificado no catálogo).
Fig. 3 Novos locais de arquivos
Fig. 4 Arquivo ausente
Também gostaríamos de salientar que uma vez que copiamos o arquivo, perdemos as permissões anteriores no arquivo e o SQL Server não poderá abrir o arquivo quando tentarmos colocar o banco de dados online. Devemos editar as permissões do arquivo e adicionar permissões completas à conta NT SERVICE\MSSQLSERVER no arquivo.
Fig. 5 Copie o arquivo de dados
Fig. 6 Permissões no Destino
Fig. 7a Permissões na Fonte
Fig. 7b Permissões na Fonte
Se tentarmos colocar o banco de dados online novamente com essas permissões ausentes, obteremos um erro 0x5 (Acesso negado). Se fizermos algo como mover o arquivo de dados usando um trabalho de agente, descobriremos que a conta do SQL Server Agent adquire a propriedade do arquivo e podemos trazer o banco de dados apenas porque a conta do SQL Server Agent é a mesma que a conta do SQL Server.
Fig. 8 Acesso negado em novo arquivo de dados
Supondo que você esteja tentando colocar o banco de dados online usando a GUI do SSMS, você verá esses erros no Visualizador de Eventos, bem como no log de erros do SQL Server, se observar atentamente. Além disso, se você estivesse usando a segunda abordagem (reiniciar a instância inteira), observaria que o banco de dados ficaria travado no estágio de recuperação. Examinar o Log de Erros lhe diria o que realmente está acontecendo.
Listando 2 arquivos de dados móveis usando um trabalho de agente
/* ==Scripting Parameters== Source Server Version : SQL Server 2017 (14.0.3023) Source Database Engine Edition : Microsoft SQL Server Standard Edition Source Database Engine Type : Standalone SQL Server Target Server Version : SQL Server 2017 Target Database Engine Edition : Microsoft SQL Server Standard Edition Target Database Engine Type : Standalone SQL Server */ USE [msdb] GO /****** Object: Job [MoveDataFile] Script Date: 7/12/2018 12:33:55 AM ******/ BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 /****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 7/12/2018 12:33:56 AM ******/ IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name = N'[Uncategorized (Local)]' AND category_class = 1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class = N'JOB' ,@type = N'LOCAL' ,@name = N'[Uncategorized (Local)]' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name = N'MoveDataFile' ,@enabled = 1 ,@notify_level_eventlog = 0 ,@notify_level_email = 0 ,@notify_level_netsend = 0 ,@notify_level_page = 0 ,@delete_level = 0 ,@description = N'No description available.' ,@category_name = N'[Uncategorized (Local)]' ,@owner_login_name = N'sa' ,@job_id = @jobId OUTPUT IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [MoveDataFile] Script Date: 7/12/2018 12:33:56 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'MoveDataFile' ,@step_id = 1 ,@cmdexec_success_code = 0 ,@on_success_action = 1 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'PowerShell' ,@command = N'Copy-Item -Path M:\MSSQL\Data\WWI_UserData1.ndf N:\MSSQL\Data\WWI_UserData1.ndf' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId ,@start_step_id = 1 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId ,@server_name = N'(local)' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@trancount > 0) ROLLBACK TRANSACTION EndSave: GO
Fig. 9 Permissões no arquivo de dados ao usar o trabalho do agente
Fig. 10 Banco de dados on-line
Automatizando o processo
Apenas por diversão, podemos decidir usar o SQL Server Agent Job para todo o processo. Configuramos uma etapa de trabalho para cada etapa do nosso processo. Isso pode ser útil se você quiser ser um DBA superstar e agendar essa migração durante a noite enquanto você vai para casa e relaxa com a família. Definitivamente, você deseja garantir que você configure uma notificação para disparar quando o trabalho for bem-sucedido, para ter certeza de que realmente será feito enquanto você estiver ausente.
Lista 3 Executando a tarefa usando um trabalho de agente
/* ==Scripting Parameters== Source Server Version : SQL Server 2017 (14.0.3023) Source Database Engine Edition : Microsoft SQL Server Standard Edition Source Database Engine Type : Standalone SQL Server Target Server Version : SQL Server 2017 Target Database Engine Edition : Microsoft SQL Server Standard Edition Target Database Engine Type : Standalone SQL Server */ USE [msdb] GO /****** Object: Job [MoveDataFile] Script Date: 7/12/2018 12:46:47 AM ******/ BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 /****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 7/12/2018 12:46:47 AM ******/ IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name = N'[Uncategorized (Local)]' AND category_class = 1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class = N'JOB' ,@type = N'LOCAL' ,@name = N'[Uncategorized (Local)]' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name = N'MoveDataFile' ,@enabled = 1 ,@notify_level_eventlog = 0 ,@notify_level_email = 3 ,@notify_level_netsend = 0 ,@notify_level_page = 0 ,@delete_level = 0 ,@description = N'No description available.' ,@category_name = N'[Uncategorized (Local)]' ,@owner_login_name = N'sa' ,@notify_email_operator_name = N'DBA' ,@job_id = @jobId OUTPUT IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [Set Database Offline] Script Date: 7/12/2018 12:46:47 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'Set Database Offline' ,@step_id = 1 ,@cmdexec_success_code = 0 ,@on_success_action = 3 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'TSQL' ,@command = N'ALTER DATABASE BranchDB SET OFFLINE;' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [MoveDataFile] Script Date: 7/12/2018 12:46:47 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'MoveDataFile' ,@step_id = 2 ,@cmdexec_success_code = 0 ,@on_success_action = 3 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'PowerShell' ,@command = N'Copy-Item -Path M:\MSSQL\Data\WWI_UserData1.ndf N:\MSSQL\Data\WWI_UserData1.ndf' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [ModifyFile and Bring Online] Script Date: 7/12/2018 12:46:47 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'ModifyFile and Bring Online' ,@step_id = 3 ,@cmdexec_success_code = 0 ,@on_success_action = 1 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'TSQL' ,@command = N' ALTER DATABASE BranchDB MODIFY FILE ( NAME = WWI_UserData, FILENAME = ''N:\MSSQL\Data\WWI_UserDataNew.ndf'' ); ALTER DATABASE BranchDB SET ONLINE;' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId ,@start_step_id = 1 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId ,@server_name = N'(local)' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@trancount > 0) ROLLBACK TRANSACTION EndSave: GO
Conclusão
Neste artigo, vimos uma maneira de mover arquivos de banco de dados do usuário no SQL Server. Também vimos a necessidade de nos certificarmos de dar atenção às permissões no arquivo de dados no novo local para que não encontremos erros ao colocar o banco de dados online novamente. Também vimos que podemos colocar tudo isso em um trabalho do SQL Server Agent usando os subsistemas T-SQL e PowerShell. Em um artigo subsequente, veremos dois outros métodos de mover arquivos de banco de dados para um novo volume.
Leitura adicional:
Mover arquivos de dados no SQL Server – Parte 2