Inleiding
Er zijn een aantal situaties die het verplaatsen van databasebestanden of transactielogbestanden van het ene volume naar het andere op dezelfde server rechtvaardigen. Deze kunnen zijn:
- De noodzaak om het volume te formatteren in de veronderstelling dat het niet correct was geformatteerd toen SQL Server werd geïnstalleerd . Bedenk dat bij het installeren van SQL Server het wordt aanbevolen om de grootte van de toewijzingseenheid van 64 kB te gebruiken om de volumes te formatteren. Als dit niet wordt gedaan op het moment van installatie en later moet worden gedaan, moet er uiteraard een back-up van de database worden bewaard of moet een nieuw, correct geformatteerd volume worden gemaakt en de database naar dit nieuwe volume worden verplaatst.
- De noodzaak om een nieuw volume te gebruiken, ervan uitgaande dat de limieten voor de onderliggende opslag zijn bereikt . Een goed voorbeeld is de 2TB-limiet van een VMware Data Store. Dit is het geval vanaf Vsphere 5.0. Hogere versies van Vsphere hebben veel hogere limieten.
- De noodzaak om de prestaties te verbeteren door IO te beheren . Nog een reden waarom u gegevensbestanden wilt verplaatsen, zijn de prestaties. Er zijn gevallen waarin een database wordt gemaakt met meerdere gegevensbestanden die allemaal op één schijf staan totdat het duidelijk wordt, naarmate de database groeit, dat u een "hot region" in de opslaglaag hebt gecreëerd. Een oplossing zou zijn het maken van nieuwe gegevensbestanden en het opnieuw opbouwen van geclusterde indexen, een andere zou het verplaatsen van gegevensbestanden zijn.
Scenario één:gebruikersdatabases verplaatsen
De stappen bij het verplaatsen van een gebruikersdatabase omvatten de volgende:
- De database offline halen
- Update de systeemcatalogus met de nieuwe locatie
- Kopieer het gegevensbestand fysiek naar de nieuwe locatie
- Breng de database online
Lijst 1 toont de uitgevoerde commando's om deze stappen te bereiken.
Lijst 1 Gegevensbestanden verplaatsen
-- 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');
Het is belangrijk op te merken dat bij het offline halen van een database het aantal actieve sessies het proces kan vertragen. Het zou een goed idee zijn om een downtime te plannen om deze taak uit te voeren. Tijdens een dergelijke uitvaltijd moet de eigenaar van de toepassing de verbinding van de toepassingsservices met de database stopzetten voordat de DBA probeert de database offline te halen. Er zijn gevallen waarin het niet zo handig is om de database offline te halen, dan is het afsluiten van de instance de beste optie. In zo'n geval zou de aanpak iets anders zijn:
- Update de systeemcatalogus met de nieuwe locatie
- Sluit de instantie af
- Kopieer het gewenste databestand fysiek naar de nieuwe locatie
- Start de instantie op
In beide benaderingen is het concept hetzelfde:het gaat om het bijwerken van de systeemcatalogus in de hoofddatabase en het vervolgens fysiek verplaatsen van het gewenste gegevensbestand. In beide gevallen moet het databestand netjes worden afgesloten. Laten we eens kijken naar de stappen bij de eerste benadering.
Fig. 1 Controleer de locatie van gegevensbestanden
De eerste stap zou zijn om te beginnen met het controleren van de stand van zaken. Ga verder om de database offline te zetten en de systeemcatalogus aan te passen.
Fig. 2 Database offline instellen en catalogus wijzigen
Zoals te zien is in Fig. 3, vertelt het opvragen van sys.master_files ons, zodra we de catalogus hebben bijgewerkt, de nieuwe locatie waar de hoofddatabase verwacht dat het gegevensbestand zich bevindt, ongeacht of we het bestand fysiek hebben verplaatst. In Fig. 4 zien we ook dat het niet mogelijk is om de database online te brengen zonder eerst het bestand fysiek naar de nieuwe locatie te verplaatsen (en het bestand te hernoemen zodat het overeenkomt met de nieuwe naam die in de catalogus is gespecificeerd).
Fig. 3 Nieuwe bestandslocaties
Afb. 4 Ontbrekend bestand
We willen er ook op wijzen dat zodra we het bestand kopiëren, we de eerdere machtigingen op het bestand verliezen en SQL Server het bestand niet kan openen wanneer we proberen de database online te brengen. We moeten de bestandsmachtigingen bewerken en het account NT SERVICE\MSSQLSERVER volledige machtigingen voor het bestand verlenen.
Fig. 5 Kopieer het gegevensbestand
Fig. 6 Toestemmingen op bestemming
Fig. 7a Toestemmingen bij de bron
Fig. 7b Toestemmingen bij de bron
Als we zouden proberen om de database weer online te brengen terwijl deze machtigingen ontbreken, krijgen we een foutmelding 0x5 (Toegang geweigerd). Als we zoiets zouden doen als het gegevensbestand verplaatsen met behulp van een agenttaak, zien we dat het SQL Server Agent-account het eigendom van het bestand verwerft en dat we de database alleen kunnen brengen omdat het SQL Server Agent-account hetzelfde is als het SQL Server-account.
Fig. 8 Toegang geweigerd op nieuw gegevensbestand
Ervan uitgaande dat u probeerde de database online te brengen met behulp van de SSMS GUI, zou u deze fouten zowel in Logboeken als in het foutenlogboek van SQL Server zien als u goed kijkt. Bovendien, als u de tweede benadering zou gebruiken (het hele exemplaar opnieuw opstarten), zou u zien dat de database vast zou blijven zitten in de herstelfase. Als u het foutenlogboek bekijkt, weet u wat er werkelijk aan de hand is.
Opsomming van 2 gegevensbestanden verplaatsen met behulp van een agenttaak
/* ==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 Rechten op gegevensbestand bij gebruik van Agent Job
Afb. 10 Database online
Het proces automatiseren
Gewoon voor de lol kunnen we besluiten om SQL Server Agent Job voor het hele proces te gebruiken. We configureren een taakstap voor elke stap van ons proces. Dit kan handig zijn als u een superster-DBA wilt zijn en een dergelijke migratie 's nachts wilt plannen terwijl u naar huis gaat en met familie ontspant. U wilt er zeker van zijn dat u een melding configureert die wordt geactiveerd wanneer de taak slaagt, zodat u zeker weet dat deze ook daadwerkelijk wordt uitgevoerd terwijl u weg bent.
Lijst 3 De taak uitvoeren met een agenttaak
/* ==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
Conclusie
In dit artikel hebben we een manier gezien om gebruikersdatabasebestanden in SQL Server te verplaatsen. We hebben ook de noodzaak gezien om ervoor te zorgen dat we aandacht besteden aan de rechten op het databestand op de nieuwe locatie, zodat we geen fouten tegenkomen bij het weer online brengen van de database. We hebben ook gezien dat we deze allemaal in een SQL Server Agent-taak kunnen plaatsen met behulp van de T-SQL- en PowerShell-subsystemen. In een volgend artikel zullen we twee andere methoden zien om databasebestanden naar een nieuw volume te verplaatsen.
Verder lezen:
Gegevensbestanden verplaatsen in SQL Server – Deel 2