J'utilise Powershell pour ce genre de travail. En fait, j'utilise Powershell pour générer Powershell, car j'ai un script qui va parcourir mes bases de données et générer mon script de déplacement final. Vous devrez déplacer chaque base de données une par une, mais cela vous aidera au moins à scénariser 90% du travail.
#load SMO
Add-PSSnapin SqlServerCmdletSnapin100
Add-PSSnapin SqlServerProviderSnapin100#Added line ifusing SQL Server 2012or later
Import-module SQLPS[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO')| out-null#Create server object and output filename $server = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server "localhost"$outputfile=([Environment]::GetFolderPath("MyDocuments"))+"\FileMover.ps1"#set this for your new location$newloc="X:\NewDBLocation"#get your databases$db_list=$server.Databases#build initial script components"Add-PSSnapin SqlServerCmdletSnapin100">$outputfile"Add-PSSnapin SqlServerProviderSnapin100">>$outputfile"Import-Module SQLPS">>$outputfile "[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') `"localhost`" | out-null">>$outputfile"`$server = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server ">>$outputfile
foreach($db_build in$db_list){#only process user databasesif(!($db_build.IsSystemObject)){#script out all the file moves"#----------------------------------------------------------------------">>$outputfile"`$db=`$server.Databases[`""+$db_build.Name+"`"]">>$outputfile$dbchange =@()$robocpy =@()
foreach ($fg in$db_build.Filegroups){
foreach($filein$fg.Files){$shortfile=$file.Filename.Substring($file.Filename.LastIndexOf('\')+1)
$oldloc=$file.Filename.Substring(0,$file.Filename.LastIndexOf('\'))
$dbchange+="`$db.FileGroups[`""+$fg.Name+"`"].Files[`""+$file.Name+"`"].Filename=`"$newloc`\"+$shortfile+"`""
$robocpy+="ROBOCOPY `"$oldloc`" `"$newloc`" $shortfile /copyall /mov"
}
}
foreach($logfile in $db_build.LogFiles)
{
$shortfile=$logfile.Filename.Substring($logfile.Filename.LastIndexOf('\')+1)
$oldloc=$logfile.Filename.Substring(0,$logfile.Filename.LastIndexOf('\'))$dbchange+="`$db.LogFiles[`""+$logfile.Name+"`"].Filename=`"$newloc`\"+$shortfile+"`""$robocpy+="ROBOCOPY `"$oldloc`" `"$newloc`" $shortfile /copyall /mov"}$dbchange+="`$db.Alter()"$dbchange+="Invoke-Sqlcmd -Query `"ALTERDATABASE["+$db_build.Name+"]SET OFFLINE WITHROLLBACK IMMEDIATE;`" -Database `"master`""$dbchange >>$outputfile$robocpy >>$outputfile"Invoke-Sqlcmd -Query `"ALTERDATABASE["+$db_build.Name+"]SET ONLINE;`" -Database `"master`"">>$outputfile}}
La sortie sera un script FileMover.ps1 dans votre dossier MyDocuments qui ressemble à ceci:
Le script déplace tous les fichiers, quel que soit leur emplacement source, vers la même destination. Vous devrez modifier les chemins de localisation personnalisés.
Le script est conçu pour s'exécuter sur le serveur sur lequel vous devez déplacer les fichiers (voir toutes les utilisations de localhost '). Remplacez localhost par votre nom d'instance si vous l'exécutez à distance.
L'utilisateur sous lequel vous l'exécutez doit avoir accès à tous les chemins de dossier impliqués dans le déplacement, à la fois pour mettre à jour les informations de nom de fichier du serveur SQL et pour déplacer les fichiers.
J'utilise InvokeSQLCmd pour une exécution hors ligne / en ligne en raison de la nature géniale des méthodes .SetOffline () et .SetOnline. J'ai trouvé que c'était plus fiable.
@MikeFal J'ai vu que vous aviez approuvé la modification. Puisque la question est étiquetée avec 2008R2, l'ajout ne devrait-il pas être plus évident (gras ou quelque chose)? (Je n'en ai aucune idée, mais je suppose que cela pourrait ne pas fonctionner ou casser quelque chose dans une version autre que 2012).
ypercubeᵀᴹ
1
J'y ai pensé et je l'ai exécuté sur SQL Server 2012 R2 - cela génère des erreurs avec les applets de commande Add-PSSnapin SqlServerCmdletSnapin100, mais traite aussi longtemps que le module d'importation SQLPS est inclus avant la partie principale du script le processus s'exécute. Techniquement, cela devrait avoir une meilleure vérification des erreurs autour de cela, mais je me suis dit que ce serait une bonne modification rapide pour aider quelqu'un d'autre qui n'était peut-être pas en mesure de trouver le besoin du module d'importation SQLPS s'il est sur un version plus récente.
Chad Rexin
1
Merci beaucoup. Petit problème cependant. Les noms de fichiers robocopy ne sont pas cités ici. Si vous avez créé des noms de base de données avec des espaces, cela ne fonctionne pas très bien.
Tim Brigham
7
Vous pouvez utiliser les méthodes Modifier la base de données Modifier le fichier ou Détacher / Attacher.
Remarque: les deux nécessiteront un certain temps d'arrêt, donc doit être fait pendant la fenêtre de maintenance.
Cela suppose que vous avez la même structure de répertoires sur le nouveau lecteur, par exemple C: \ data \ et D: \ Data.
- utilisation de la base de données Alter avec la méthode Modify (préférée)
SET NOCOUNT ONDECLARE@datafile VARCHAR(255),@logfile VARCHAR(255),@dbid TINYINT
,@SQLText VARCHAR(max),@dbname VARCHAR(255),@sqltext1 VARCHAR(max),@SQLText2 VARCHAR(max)--2. Prepare for modifyIFEXISTS(SELECT1FROM tempdb..sysobjects
WHERE NAME LIKE'%#filetable%')BEGINDROPTABLE#filetable
ENDCREATETABLE#filetable (
mdf VARCHAR(255),ldf VARCHAR(255),dbid TINYINT
,dbname VARCHAR(100),fileid TINYINT
,logicalname SYSNAME
)--INSERT#filetable (
mdf
,dbid
,fileid
,logicalname
)SELECT physical_name
,database_id
,data_space_id
,NAME
FROM sys.master_files
WHERE data_space_id =1INSERT#filetable (
ldf
,dbid
,fileid
,logicalname
)SELECT physical_name
,database_id
,data_space_id
,NAME
FROM sys.master_files
WHERE data_space_id =0UPDATE u
SET u.dbname = s.NAME
FROM#filetable u
INNERJOIN master..sysdatabases s ON u.dbid = s.dbid
UPDATE#filetable
SET mdf = replace(mdf,'C:','D:'),ldf = replace(ldf,'C:','D:')FROM#filetable
SELECT@dbid = min(dbid)FROM#filetable
WHERE dbid >4WHILE@dbid ISNOTNULLBEGINSELECT@SQLText ='alter database ['+ dbname +'] MODIFY FILE (Name = '+ logicalname +' , FileName = N'''+ ldf +''');'FROM#filetable
WHERE dbid =convert(VARCHAR,@dbid)AND fileid =0-- Log filePRINT@SQLText
--Exec(@SQLText)SELECT@SQLText2 ='alter database ['+ dbname +'] MODIFY FILE (Name = '+ logicalname +' , FileName = N'''+ mdf +''');'FROM#filetable
WHERE dbid =convert(VARCHAR,@dbid)AND fileid =1-- data filePRINT@SQLText2
--Exec(@SQLText)SELECT@dbid = min(dbid)FROM#filetable
WHERE dbid >4AND dbid >@dbid
END
--- en utilisant la méthode Old Detach / Attach (pas préféré, mais les gens l'utilisent encore .. malheureusement je l'ai utilisé récemment sur un serveur NON prod).
DECLARE@datafile VARCHAR(255),@logfile VARCHAR(255),@dbid TINYINT
,@SQLText VARCHAR(8000),@dbname VARCHAR(255),@SQLText2 VARCHAR(8000)--2. Detach All Local Databases and prepare for AttachIFEXISTS(SELECT1FROM tempdb..sysobjects
WHERE NAME LIKE'%#filetable%')BEGINDROPTABLE#filetable
ENDCREATETABLE#filetable (
mdf VARCHAR(255),ldf VARCHAR(255),dbid TINYINT
,dbname VARCHAR(100),fileid TINYINT
)--INSERT#filetable (
mdf
,dbid
,fileid
)SELECT physical_name
,database_id
,data_space_id
FROM sys.master_files
WHERE data_space_id =1INSERT#filetable (
ldf
,dbid
,fileid
)SELECT physical_name
,database_id
,data_space_id
FROM sys.master_files
WHERE data_space_id =0UPDATE u
SET u.dbname = s.NAME
FROM#filetable u
INNERJOIN master..sysdatabases s ON u.dbid = s.dbid
UPDATE#filetable
SET mdf = replace(mdf,'C:','D:'),ldf = replace(ldf,'C:','D:')FROM#filetable
SELECT@dbid = min(dbid)FROM#filetable
WHERE dbid >4WHILE@dbid ISNOTNULLBEGINSELECT@SQLText ='alter database ['+ dbname +']'FROM#filetable
WHERE dbid =convert(VARCHAR,@dbid)SELECT@SQLText =@SQLText + CHAR(10)+' set single_user with rollback immediate;'SELECT@SQLText =@SQLText + CHAR(10)+' exec master..sp_detach_db '+ dbname
FROM#filetable
WHERE dbid =convert(VARCHAR,@dbid)PRINT@SQLText
--Exec(@SQLText)SELECT@SQLText2 ='exec master..sp_attach_db '''+ dbname +''''FROM#filetable
WHERE dbid =@dbid
SELECT@SQLText2 =@SQLText2 +','''+ mdf +''''FROM#filetable
WHERE dbid =@dbid
AND mdf ISNOTNULLSELECT@SQLText2 =@SQLText2 +','''+ ldf +''''FROM#filetable
WHERE dbid =@dbid
AND ldf ISNOTNULLPRINT@SQLText2
--Exec(@SQLText)SELECT@dbid = min(dbid)FROM#filetable
WHERE dbid >4AND dbid >@dbid
ENDDROPTABLE#filetable
La seule façon que je sache de faire plusieurs bases de données à la fois serait de scripter le déplacement de plusieurs bases de données à la fois.
ALTERDATABASE database_nameA SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameB SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameC SET OFFLINE WITHROLLBACK IMMEDIATE;-------
Ici, vous pouvez soit déplacer les fichiers manuellement, soit écrire un script pour le faire. Peut-être en utilisant xp_cmdshell ou un outil. Probablement plus facile de déplacer simplement les fichiers à la main. Marquez-en un tas, puis glissez-déposez.
-------ALTERDATABASE database_nameA MODIFY FILE( NAME = logical_name, FILENAME ='new_path\os_file_name');ALTERDATABASE database_nameB MODIFY FILE( NAME = logical_name, FILENAME ='new_path\os_file_name');ALTERDATABASE database_nameC MODIFY FILE( NAME = logical_name, FILENAME ='new_path\os_file_name');ALTERDATABASE database_nameA SET ONLINE;ALTERDATABASE database_nameB SET ONLINE;ALTERDATABASE database_nameC SET ONLINE;
Bien sûr, si vous déplacez le fichier de données et le fichier journal, vous devez vous assurer de faire la partie MODIFY FILE pour chaque partie.
Ce script renverra un lot d'instructions que vous pouvez exécuter.
SELECT d.name as db, f.name, physical_name, f.state_desc,'ALTER DATABASE ['+d.name+'] MODIFY FILE (name='''+f.name+''' ,filename='''+replace(physical_name,'C:\database','D:\whatever')+'''); 'as DetachCommand,'ALTER DATABASE ['+d.name+'] SET ONLINE'as ReattachCommand
from sys.master_files f
innerjoin sys.databases d on d.database_id=f.database_id
Vous pouvez utiliser les méthodes Modifier la base de données Modifier le fichier ou Détacher / Attacher.
Remarque: les deux nécessiteront un certain temps d'arrêt, donc doit être fait pendant la fenêtre de maintenance.
Cela suppose que vous avez la même structure de répertoires sur le nouveau lecteur, par exemple C: \ data \ et D: \ Data.
- utilisation de la base de données Alter avec la méthode Modify (préférée)
--- en utilisant la méthode Old Detach / Attach (pas préféré, mais les gens l'utilisent encore .. malheureusement je l'ai utilisé récemment sur un serveur NON prod).
la source
La seule façon que je sache de faire plusieurs bases de données à la fois serait de scripter le déplacement de plusieurs bases de données à la fois.
Ici, vous pouvez soit déplacer les fichiers manuellement, soit écrire un script pour le faire. Peut-être en utilisant xp_cmdshell ou un outil. Probablement plus facile de déplacer simplement les fichiers à la main. Marquez-en un tas, puis glissez-déposez.
Bien sûr, si vous déplacez le fichier de données et le fichier journal, vous devez vous assurer de faire la partie MODIFY FILE pour chaque partie.
la source
la source
Ce script renverra un lot d'instructions que vous pouvez exécuter.
la source