Introduzione
Esistono diverse situazioni che giustificherebbero lo spostamento di file di database o file di registro delle transazioni da un volume all'altro sullo stesso server. Questi possono includere:
- La necessità di formattare il volume presupponendo che non fosse formattato correttamente al momento dell'installazione di SQL Server . Ricordiamo che durante l'installazione di SQL Server, si consiglia di utilizzare la dimensione dell'unità di allocazione di 64 KB per formattare i volumi. Se ciò non viene eseguito al momento dell'installazione e deve essere eseguito in un secondo momento, sarà ovviamente necessario conservare un backup del database prima o creare un nuovo volume correttamente formattato e spostare il database su questo nuovo volume.
- La necessità di utilizzare un nuovo volume presupponendo che siano stati raggiunti i limiti per lo storage sottostante . Un buon esempio potrebbe essere il limite di 2 TB di un VMware Data Store. Questo è il caso di VSphere 5.0. Le versioni superiori di VSphere hanno limiti molto più elevati.
- La necessità di migliorare le prestazioni gestendo l'IO . Un altro motivo per cui potresti voler spostare i file di dati è la prestazione. Ci sono casi in cui un database viene creato con più file di dati tutti su un disco fino a quando non diventa ovvio, man mano che il database cresce, che hai creato una "regione calda" nel livello di archiviazione. Una soluzione potrebbe essere la creazione di nuovi file di dati e la ricostruzione di indici cluster, un'altra lo spostamento dei file di dati.
Scenario uno:spostamento dei database degli utenti
I passaggi coinvolti nello spostamento di un database utente implicano quanto segue:
- Porta il database offline
- Aggiorna il catalogo del sistema con la nuova posizione
- Copia fisicamente il file di dati nella nuova posizione
- Porta il database online
Il Listato 1 mostra i comandi eseguiti per ottenere questi passaggi.
Elenco 1 Spostamento di file di dati
-- 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 notare che quando si porta offline un database, il numero di sessioni attive può ritardare il processo. Pianificare un tempo di inattività per eseguire questa attività sarebbe una buona idea. Durante tale periodo di inattività, il proprietario dell'applicazione deve interrompere la connessione dei servizi dell'applicazione al database prima che il DBA tenti di portare il database offline. Ci sono casi in cui non è così conveniente portare il database offline, quindi spegnere l'istanza sarebbe l'opzione migliore. In tal caso l'approccio sarebbe leggermente diverso:
- Aggiorna il catalogo del sistema con la nuova posizione
- Chiudi l'istanza
- Copia fisicamente il file di dati desiderato nella nuova posizione
- Avvia l'istanza
In entrambi gli approcci, il concetto è lo stesso:si tratta di aggiornare il catalogo di sistema nel database principale e quindi di riposizionare fisicamente il file di dati desiderato. In entrambi i casi, il file di dati deve essere chiuso in modo pulito. Diamo un'occhiata ai passaggi coinvolti nel primo approccio.
Fig. 1 Verifica la posizione dei file di dati
Il primo passo sarebbe controllare lo stato delle cose con cui iniziare. Procedi per impostare il database offline e modificare il catalogo di sistema.
Fig. 2 Imposta il database offline e modifica il catalogo
Come mostrato in Fig. 3, una volta aggiornato il catalogo, la query sys.master_files ci dice la nuova posizione in cui il database master si aspetta che si trovi il file di dati indipendentemente dal fatto che abbiamo spostato fisicamente il file o meno. In Fig. 4, vediamo anche che non è possibile portare il database online senza prima spostare fisicamente il file nella nuova posizione (e rinominare il file in modo che corrisponda al nuovo nome specificato nel catalogo).
Fig. 3 Nuove posizioni dei file
Fig. 4 File mancante
Segnaliamo inoltre che una volta copiato il file, perdiamo le autorizzazioni precedenti sul file e SQL Server non sarà in grado di aprire il file quando tenteremo di portare il database online. Dobbiamo modificare le autorizzazioni del file e aggiungere concedere all'account NT SERVICE\MSSQLSERVER le autorizzazioni complete sul file.
Fig. 5 Copia il file di dati
Fig. 6 Autorizzazioni a destinazione
Fig. 7a Autorizzazioni all'origine
Fig. 7b Autorizzazioni alla fonte
Se dovessimo tentare di riportare il database online con queste autorizzazioni mancanti, riceveremo un errore 0x5 (Accesso negato). Se dovessimo fare qualcosa come spostare il file di dati utilizzando un processo dell'agente, scopriamo che l'account di SQL Server Agent acquisisce la proprietà del file e possiamo portare il database solo perché l'account di SQL Server Agent è lo stesso dell'account di SQL Server.
Fig. 8 Accesso negato su nuovo file di dati
Supponendo che tu stia tentando di portare il database online utilizzando la GUI di SSMS, se guardi da vicino vedresti questi errori nel Visualizzatore eventi e nel registro degli errori di SQL Server. Inoltre, se si utilizza il secondo approccio (riavvio dell'intera istanza), si osserva che il database si blocca nella fase di ripristino. L'esame del registro degli errori ti direbbe cosa sta realmente accadendo.
Elenco 2 Spostamento di file di dati utilizzando un processo 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 Autorizzazioni sul file di dati quando si utilizza il lavoro dell'agente
Fig. 10 Database in linea
Automatizzazione del processo
Solo per divertimento possiamo decidere di utilizzare SQL Server Agent Job per l'intero processo. Configuriamo una fase di lavoro per ogni fase del nostro processo. Questo può essere utile se vuoi essere un DBA superstar e pianificare una tale migrazione durante la notte mentre vai a casa e ti rilassi con la famiglia. Sicuramente vorrai assicurarti di configurare una notifica da attivare quando il lavoro ha esito positivo, in modo da essere sicuro che venga effettivamente eseguito mentre sei via.
Listato 3 Esecuzione dell'attività utilizzando un processo 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
Conclusione
In questo articolo, abbiamo visto un modo per spostare i file di database degli utenti in SQL Server. Abbiamo anche riscontrato la necessità di prestare attenzione ai permessi sul file di dati nella nuova posizione in modo da non riscontrare errori quando si riporta il database online. Abbiamo anche visto che è possibile inserire tutti questi elementi in un processo di SQL Server Agent utilizzando i sottosistemi T-SQL e PowerShell. In un articolo successivo vedremo altri due metodi per spostare i file di database in un nuovo volume.
Ulteriori letture:
Sposta i file di dati in SQL Server – Parte 2