Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

So verschieben Sie Datendateien in SQL Server – Teil 1

Einführung

Es gibt eine Reihe von Situationen, die das Verschieben von Datenbankdateien oder Transaktionsprotokolldateien von einem Volume auf ein anderes auf demselben Server rechtfertigen würden. Dazu können gehören:

  1. Die Notwendigkeit, das Volume zu formatieren, wenn angenommen wird, dass es bei der Installation von SQL Server nicht richtig formatiert wurde . Denken Sie daran, dass bei der Installation von SQL Server empfohlen wird, die Größe der Zuordnungseinheiten von 64 KB zum Formatieren der Volumes zu verwenden. Wenn dies nicht zum Zeitpunkt der Installation erfolgt und später durchgeführt werden muss, ist es natürlich erforderlich, zuerst eine Sicherungskopie der Datenbank aufzubewahren oder ein neues, ordnungsgemäß formatiertes Volume zu erstellen und die Datenbank auf dieses neue Volume zu verschieben.
  2. Die Notwendigkeit, ein neues Volume zu verwenden, vorausgesetzt, die Grenzwerte für den zugrunde liegenden Speicher wurden erreicht . Ein gutes Beispiel wäre die 2-TB-Grenze eines VMware-Datenspeichers. Dies ist ab VSphere 5.0 der Fall. Höhere Versionen von VSphere haben viel höhere Limits.
  3. Die Notwendigkeit, die Leistung durch die Verwaltung von IO zu verbessern . Ein weiterer Grund für das Verschieben von Datendateien ist die Leistung. Es gibt Fälle, in denen eine Datenbank mit mehreren Datendateien erstellt wird, die sich alle auf einer Festplatte befinden, bis es offensichtlich wird, wenn die Datenbank wächst, dass Sie eine „heiße Region“ in der Speicherschicht erstellt haben. Eine Lösung wäre das Erstellen neuer Datendateien und das Neuaufbauen von Clustered-Indizes, eine andere das Verschieben von Datendateien.

Szenario 1:Verschieben von Benutzerdatenbanken

Die Schritte zum Verschieben einer Benutzerdatenbank umfassen die folgenden:

  1. Schalten Sie die Datenbank offline
  2. Aktualisieren Sie den Systemkatalog mit dem neuen Standort
  3. Kopieren Sie die Datendatei physisch an den neuen Speicherort
  4. Bringen Sie die Datenbank online

Listing 1 zeigt die Befehle, die ausgeführt werden, um diese Schritte auszuführen.

Listing 1 Verschieben von Datendateien

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

Es ist wichtig zu beachten, dass beim Offlineschalten einer Datenbank die Anzahl aktiver Sitzungen den Vorgang verzögern kann. Es wäre eine gute Idee, eine Ausfallzeit einzuplanen, um diese Aufgabe auszuführen. Während einer solchen Ausfallzeit sollte der Anwendungseigentümer die Verbindung der Anwendungsdienste mit der Datenbank beenden, bevor der DBA versucht, die Datenbank offline zu schalten. Es gibt Fälle, in denen es nicht so bequem ist, die Datenbank offline zu schalten, dann wäre das Herunterfahren der Instanz die beste Option. In einem solchen Fall wäre der Ansatz etwas anders:

  1. Aktualisieren Sie den Systemkatalog mit dem neuen Standort
  2. Fahren Sie die Instanz herunter
  3. Kopieren Sie die gewünschte Datendatei physisch an den neuen Speicherort
  4. Starten Sie die Instanz

Bei beiden Ansätzen ist das Konzept dasselbe:Es umfasst das Aktualisieren des Systemkatalogs in der Master-Datenbank und das anschließende physische Verschieben der gewünschten Datendatei. In beiden Fällen muss die Datei sauber geschlossen werden. Werfen wir einen Blick auf die Schritte des ersten Ansatzes.

Abb. 1 Überprüfen Sie den Speicherort der Datendateien

Der erste Schritt wäre, den Ausgangszustand zu prüfen. Fahren Sie damit fort, die Datenbank offline zu setzen und den Systemkatalog zu ändern.

Abb. 2 Datenbank offline setzen und Katalog ändern

Wie in Abb. 3 zu sehen ist, teilt uns die Abfrage von sys.master_files nach der Aktualisierung des Katalogs den neuen Speicherort mit, an dem die Master-Datenbank die Datendatei erwartet, unabhängig davon, ob wir die Datei physisch verschoben haben oder nicht. In Abb. 4 sehen wir auch, dass es nicht möglich ist, die Datenbank online zu bringen, ohne zuerst die Datei physisch an den neuen Speicherort zu verschieben (und die Datei umzubenennen, damit sie mit dem neuen Namen übereinstimmt, der im Katalog angegeben ist).

Abb. 3 Neue Dateispeicherorte

Abb. 4 Fehlende Datei

Wir möchten auch darauf hinweisen, dass wir nach dem Kopieren der Datei die vorherigen Berechtigungen für die Datei verlieren und SQL Server die Datei nicht öffnen kann, wenn wir versuchen, die Datenbank online zu bringen. Wir müssen die Dateiberechtigungen bearbeiten und dem Konto NT SERVICE\MSSQLSERVER vollständige Berechtigungen für die Datei gewähren.

Abb. 5 Kopieren Sie die Datei

Abb. 6 Berechtigungen am Ziel

Abb. 7a Berechtigungen an der Quelle

Abb. 7b Berechtigungen an der Quelle

Wenn wir versuchen würden, die Datenbank ohne diese Berechtigungen wieder online zu bringen, erhalten wir einen Fehler 0x5 (Zugriff verweigert). Wenn wir die Datendatei mithilfe eines Agentenauftrags verschieben, stellen wir fest, dass das SQL Server-Agent-Konto den Besitz der Datei erwirbt, und wir können die Datenbank nur bringen, weil das SQL Server-Agent-Konto mit dem SQL Server-Konto identisch ist.

Abb. 8 Zugriff auf neue Datei verweigert

Angenommen, Sie versuchen, die Datenbank mithilfe der SSMS-GUI online zu schalten, würden Sie diese Fehler sowohl in der Ereignisanzeige als auch im SQL Server-Fehlerprotokoll sehen, wenn Sie genau hinsehen. Wenn Sie den zweiten Ansatz verwenden (Neustart der gesamten Instanz), würden Sie außerdem feststellen, dass die Datenbank in der Wiederherstellungsphase hängen bleibt. Eine Untersuchung des Fehlerprotokolls würde Ihnen sagen, was wirklich vor sich geht.

Listing 2:Verschieben von Datendateien mit einem Agent-Job

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

Abb. 9 Berechtigungen für Datendatei bei Verwendung des Agentenjobs

Abb. 10 Datenbank online

Automatisierung des Prozesses

Nur zum Spaß können wir uns entscheiden, SQL Server Agent Job für den gesamten Prozess zu verwenden. Wir konfigurieren einen Jobschritt für jeden Schritt unseres Prozesses. Dies kann nützlich sein, wenn Sie ein Superstar-DBA werden möchten und eine solche Migration über Nacht planen, während Sie nach Hause gehen und sich mit der Familie entspannen. Auf jeden Fall sollten Sie sicherstellen, dass Sie eine Benachrichtigung konfigurieren, die ausgelöst wird, wenn der Job erfolgreich ist, damit Sie sicher sein können, dass er tatsächlich erledigt wird, während Sie weg sind.

Listing 3:Ausführen der Aufgabe mit einem Agent-Job

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

Schlussfolgerung

In diesem Artikel haben wir eine Möglichkeit gesehen, Benutzerdatenbankdateien in SQL Server zu verschieben. Wir haben auch die Notwendigkeit gesehen, sicherzustellen, dass wir die Berechtigungen für die Datendatei am neuen Speicherort beachten, damit keine Fehler auftreten, wenn wir die Datenbank wieder online bringen. Wir haben auch gesehen, dass wir all diese mithilfe der T-SQL- und PowerShell-Subsysteme in einen SQL Server-Agent-Job einfügen können. In einem späteren Artikel werden wir zwei weitere Methoden zum Verschieben von Datenbankdateien auf ein neues Volume kennenlernen.

Weiterführende Literatur:

Verschieben von Datendateien in SQL Server – Teil 2