Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como mover arquivos de dados no SQL Server – Parte 1

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:
  1. 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.
  2. 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.
  3. 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:
  1. Coloque o banco de dados offline
  2. Atualize o catálogo do sistema com o novo local
  3. Copie o arquivo de dados fisicamente para o novo local
  4. 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:
  1. Atualize o catálogo do sistema com o novo local
  2. Desligar a instância
  3. Copie o arquivo de dados desejado fisicamente para o novo local
  4. 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