sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man flyttar datafiler i SQL Server – Del 1

Introduktion

Det finns ett antal situationer som skulle motivera att databasfiler eller transaktionsloggfiler flyttas från en volym till en annan på samma server. Dessa kan inkludera:

  1. Behovet av att formatera volymen förutsatt att den inte var korrekt formaterad när SQL Server installerades . Kom ihåg att när du installerar SQL Server, rekommenderas att 64K allokeringsenhetsstorlek används för att formatera volymerna. Om detta inte görs vid installationstillfället och behöver göras senare, kommer det uppenbarligen att kräva att du bevarar en säkerhetskopia av databasen eller skapar en ny, korrekt formaterad volym och flyttar databasen till denna nya volym.
  2. Behovet av att använda en ny volym förutsatt att gränserna har nåtts för den underliggande lagringen . Ett bra exempel skulle vara gränsen på 2 TB för en VMware Data Store. Detta är fallet från VSphere 5.0. Högre versioner av VSphere har mycket högre gränser.
  3. Behovet av att förbättra prestanda genom att hantera IO . Ytterligare en anledning till att du kanske vill flytta datafiler är prestanda. Det finns fall där en databas skapas med flera datafiler som alla sitter på en disk tills det blir uppenbart, när databasen växer, att du har skapat en "het region" i lagringslagret. En lösning skulle vara att skapa nya datafiler och bygga om klustrade index, en annan skulle vara att flytta datafiler.

Scenario ett:Flytta användardatabaser

Stegen för att flytta en användardatabas innefattar följande:

  1. Ta databasen offline
  2. Uppdatera systemkatalogen med den nya platsen
  3. Kopiera datafilen fysiskt till den nya platsen
  4. Sätt databasen online

Lista 1 visar de kommandon som utförs för att uppnå dessa steg.

Listar 1 flyttande datafiler

-- 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');

Det är viktigt att notera att när du tar en databas offline kan antalet aktiva sessioner försena processen. Att schemalägga en stilleståndstid för att utföra denna uppgift skulle vara en bra idé. Under en sådan stilleståndstid bör applikationsägaren stoppa applikationstjänster från att ansluta till databasen innan DBA försöker ta databasen offline. Det finns fall där det inte är så bekvämt att ta databasen offline, då skulle det vara det bästa alternativet att stänga av instansen. I ett sådant fall skulle tillvägagångssättet vara något annorlunda:

  1. Uppdatera systemkatalogen med den nya platsen
  2. Stäng av instansen
  3. Kopiera den önskade datafilen fysiskt till den nya platsen
  4. Starta instansen

I båda tillvägagångssätten är konceptet detsamma:det innebär att uppdatera systemkatalogen i huvuddatabasen och sedan fysiskt flytta den önskade datafilen. I båda fallen måste datafilen stängas rent. Låt oss ta en titt på stegen i det första tillvägagångssättet.

Fig. 1 Verifiera platsen för datafiler

Det första steget skulle vara att kontrollera tillståndet till att börja med. Fortsätt för att ställa in databasen offline och ändra systemkatalogen.

Fig. 2 Ställ in databas offline och ändra katalog

Som framgår av fig. 3, när vi väl har uppdaterat katalogen, talar en fråga om sys.master_files om den nya plats som huvuddatabasen förväntar sig att datafilen ska vara på oavsett om vi fysiskt har flyttat filen eller inte. I fig. 4 ser vi också att det inte är möjligt att få databasen online utan att först flytta filen till den nya platsen fysiskt (och byta namn på filen för att matcha det nya namnet som anges i katalogen).

Fig. 3 Nya filplatser

Fig. 4 Fil saknas

Vi vill också påpeka att när vi väl kopierar filen förlorar vi de tidigare behörigheterna för filen och SQL Server kommer inte att kunna öppna filen när vi försöker få databasen online. Vi måste redigera filbehörigheterna och lägga till ge kontot NT SERVICE\MSSQLSERVER fullständiga behörigheter för filen.

Fig. 5 Kopiera datafilen

Fig. 6 Behörigheter vid destination

Fig. 7a Behörigheter vid källan

Fig. 7b Behörigheter vid källan

Om vi ​​skulle försöka få databasen online igen med dessa behörigheter saknas, kommer vi att få ett felmeddelande 0x5 (åtkomst nekad). Om vi ​​skulle göra något som att flytta datafilen med hjälp av ett agentjobb, upptäcker vi att SQL Server Agent-kontot förvärvar äganderätten till filen och vi kan ta med databasen bara för att SQL Server Agent-kontot är detsamma som SQL Server-kontot.

Fig. 8 Åtkomst nekad på ny datafil

Om du antar att du försökte få databasen online med SSMS GUI, skulle du se dessa fel i Event Viewer såväl som i SQL Server-felloggen om du tittar noga. Dessutom, om du använde den andra metoden (starta om hela instansen), skulle du observera att databasen skulle ha fastnat vid återställningsstadiet. Att undersöka felloggen skulle berätta vad som verkligen pågår.

Lista 2 Flytta datafiler med hjälp av ett agentjobb

/* ==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 Behörigheter för datafil vid användning av agentjobb

Fig. 10 Databas online

Automatisera processen

Bara för skojs skull kan vi välja att använda SQL Server Agent Job för hela processen. Vi konfigurerar ett jobbsteg för varje steg i vår process. Detta kan vara användbart om du vill bli en superstar DBA och schemalägga en sådan migrering över natten medan du går hem och kopplar av med familjen. Definitivt skulle du vilja se till att du konfigurerar ett meddelande så att det aktiveras när jobbet lyckas så att du är säker på att det faktiskt blir gjort när du är borta.

Lista 3 Utföra uppgiften med hjälp av ett agentjobb

/* ==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

Slutsats

I den här artikeln har vi sett ett sätt att flytta användardatabasfiler i SQL Server. Vi har också sett behovet av att se till att vi uppmärksammar behörigheterna på datafilen på den nya platsen så att vi inte stöter på fel när databasen återkopplas online. Vi har också sett att vi kan lägga alla dessa i ett SQL Server Agent-jobb med hjälp av T-SQL och PowerShell Subsystems. I en efterföljande artikel kommer vi att se två andra metoder för att flytta databasfiler till en ny volym.

Mer läsning:

Flytta datafiler i SQL Server – Del 2


  1. MySQL :Flera rader som kommaseparerad en rad

  2. Hämta datum mellan olika datumintervall

  3. Driver.getConnection hänger sig med SQLServer-drivrutinen och Java 1.6.0_29

  4. Anslutningen hänger sig efter tid av inaktivitet