sql >> Database teknologi >  >> RDS >> Sqlserver

Sådan flyttes datafiler i SQL Server - Del 1

Introduktion

Der er en række situationer, som ville berettige flytning af databasefiler eller transaktionslogfiler fra én diskenhed til en anden på den samme server. Disse kan omfatte:

  1. Behovet for at formatere volumen, forudsat at det ikke var formateret korrekt, da SQL Server blev installeret . Husk, at når du installerer SQL Server, anbefales det, at 64K allokeringsenhedsstørrelse bruges til at formatere diskenhederne. Hvis dette ikke gøres på tidspunktet for installationen og skal gøres senere, vil det naturligvis kræve, at du bevarer en sikkerhedskopi af databasen, eller at du laver en ny, korrekt formateret diskenhed og flytter databasen til denne nye diskenhed.
  2. Behovet for at bruge en ny volumen forudsat at grænserne er nået for den underliggende lagerplads . Et godt eksempel ville være grænsen på 2 TB for et VMware Data Store. Dette er tilfældet fra VSphere 5.0. Højere versioner af VSphere har meget højere grænser.
  3. Behovet for at forbedre ydeevnen ved at administrere IO . En anden grund til, at du måske ønsker at flytte datafiler, er ydeevne. Der er tilfælde, hvor en database oprettes med flere datafiler, der alle sidder på én disk, indtil det bliver tydeligt, efterhånden som databasen vokser, at du har oprettet en "hot region" i lagerlaget. En løsning ville være at oprette nye datafiler og genopbygge klyngede indekser, en anden ville være at flytte datafiler.

Scenario 1:Flytning af brugerdatabaser

De trin, der er involveret i at flytte en brugerdatabase, involverer følgende:

  1. Tag databasen offline
  2. Opdater systemkataloget med den nye placering
  3. Kopiér datafilen fysisk til den nye placering
  4. Bring databasen online

Liste 1 viser de kommandoer, der udføres for at opnå disse trin.

Visning af 1 flyttende 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 er vigtigt at bemærke, at når du tager en database offline, kan antallet af aktive sessioner forsinke processen. At planlægge en nedetid for at udføre denne opgave ville være en god idé. Under en sådan nedetid bør applikationsejeren stoppe applikationstjenesters forbindelse til databasen, før DBA forsøger at tage databasen offline. Der er tilfælde, hvor det ikke er så bekvemt at tage databasen offline, så ville det være den bedste mulighed at lukke instansen ned. I et sådant tilfælde ville tilgangen være lidt anderledes:

  1. Opdater systemkataloget med den nye placering
  2. Luk forekomsten ned
  3. Kopiér den ønskede datafil fysisk til den nye placering
  4. Start forekomsten

I begge tilgange er konceptet det samme:det involverer opdatering af systemkataloget i masterdatabasen og derefter fysisk flytning af den ønskede datafil. I begge tilfælde skal datafilen være ren lukket. Lad os tage et kig på de trin, der er involveret i den første tilgang.

Fig. 1 Bekræft placeringen af ​​datafiler

Det første skridt ville være at kontrollere tingenes tilstand til at starte med. Fortsæt med at indstille databasen offline og ændre systemkataloget.

Fig. 2 Indstil Database Offline og Rediger Katalog

Som det ses i fig. 3, når vi har opdateret kataloget, fortæller forespørgslen om sys.master_files os den nye placering, masterdatabasen forventer, at datafilen er på, uanset om vi fysisk har flyttet filen eller ej. I fig. 4 ser vi også, at det ikke er muligt at bringe databasen online uden først at flytte filen til den nye placering fysisk (og omdøbe filen, så den matcher det nye navn angivet i kataloget).

Fig. 3 Nye filplaceringer

Fig. 4 Manglende fil

Vi vil også gerne påpege, at når vi først kopierer filen, mister vi de tidligere tilladelser på filen, og SQL Server vil ikke være i stand til at åbne filen, når vi forsøger at bringe databasen online. Vi skal redigere filtilladelserne og tilføje, give kontoen NT SERVICE\MSSQLSERVER fulde tilladelser til filen.

Fig. 5 Kopier datafilen

Fig. 6 Tilladelser ved destination

Fig. 7a Tilladelser ved kilden

Fig. 7b Tilladelser ved kilden

Hvis vi skulle forsøge at bringe databasen online igen med disse tilladelser mangler, vil vi få en fejlmeddelelse 0x5 (Adgang nægtet). Hvis vi skulle gøre noget som at flytte datafilen ved hjælp af et agentjob, opdager vi, at SQL Server Agent-kontoen erhverver ejerskab af filen, og vi kan kun bringe databasen, fordi SQL Server Agent-kontoen er den samme som SQL Server-kontoen.

Fig. 8 Adgang nægtet på ny datafil

Hvis du antager, at du forsøgte at bringe databasen online ved hjælp af SSMS GUI, ville du se disse fejl i Event Viewer såvel som i SQL Server-fejlloggen, hvis du ser nøje efter. Derudover, hvis du brugte den anden tilgang (genstarter hele forekomsten), vil du observere, at databasen ville sidde fast på gendannelsesstadiet. Undersøgelse af fejlloggen ville fortælle dig, hvad der virkelig foregår.

Visning af 2 flytning af datafiler ved hjælp af et agentjob

/* ==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 Tilladelser på datafil ved brug af agentjob

Fig. 10 Database online

Automatisering af processen

For sjov kan vi beslutte at bruge SQL Server Agent Job til hele processen. Vi konfigurerer et jobtrin for hvert trin i vores proces. Dette kan være nyttigt, hvis du vil være en superstjerne DBA og planlægge en sådan migrering natten over, mens du går hjem og slapper af med familien. Du vil bestemt gerne sikre dig, at du konfigurerer en meddelelse til at udløse, når jobbet lykkes, så du er sikker på, at det rent faktisk bliver gjort, mens du er væk.

Liste 3 Udførelse af opgaven ved hjælp af et agentjob

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

Konklusion

I denne artikel har vi set en måde at flytte brugerdatabasefiler i SQL Server. Vi har også set behovet for at sørge for, at vi er opmærksomme på tilladelserne på datafilen på den nye lokation, så vi ikke støder på fejl, når vi bringer databasen online igen. Vi har også set, at vi kan lægge alle disse i et SQL Server Agent-job ved hjælp af T-SQL og PowerShell-undersystemerne. I en efterfølgende artikel vil vi se to andre metoder til at flytte databasefiler til et nyt volumen.

Yderligere læsning:

Flyt datafiler i SQL Server – Del 2


  1. Få den distinkte sum af en sammenføjet tabelkolonne

  2. Hvornår skal man bruge Common Table Expression (CTE)

  3. Hvordan HEX() virker i MariaDB

  4. Hvordan sletter man duplikerede poster?