Ich benutze Powershell für diese Art von Arbeit. Tatsächlich benutze ich Powershell, um Powershell zu generieren, da ich ein Skript habe, das meine Datenbanken durchläuft und mein endgültiges Verschiebungsskript generiert. Sie müssen jede Datenbank einzeln verschieben, dies hilft Ihnen jedoch, mindestens 90% der Arbeit per Skript auszuführen.
#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 databases
if(!($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
}}
Die Ausgabe ist ein FileMover.ps1-Skript in Ihrem MyDocuments-Ordner, das ungefähr so aussieht:
Das Skript verschiebt alle Dateien, unabhängig vom Quellspeicherort, an dasselbe Ziel. Für benutzerdefinierte Standortpfade müssen Sie Anpassungen vornehmen.
Das Skript läuft auf dem Server, auf den Sie die Dateien verschieben müssen (siehe alle Verwendungen von localhost). Ersetzen Sie localhost durch Ihren Instanznamen, wenn Sie dies remote ausführen.
Der Benutzer, den Sie ausführen, benötigt Zugriff auf alle Ordnerpfade, die an der Verschiebung beteiligt sind, sowohl zum Aktualisieren der SQL Server-Dateinameninformationen als auch zum Verschieben der Dateien.
Ich verwende InvokeSQLCmd für die Offline- / Online-Ausführung, da die Methoden .SetOffline () und .SetOnline irre sind. Ich habe festgestellt, dass dies zuverlässiger ist.
@MikeFal Ich habe gesehen, dass du der Bearbeitung zugestimmt hast. Da die Frage mit 2008R2 markiert ist, sollte der Zusatz nicht offensichtlicher sein (fett oder so)? (Ich habe keine Ahnung, aber ich vermute, dass es in einer anderen Version als 2012 möglicherweise nicht funktioniert oder etwas kaputt geht.)
ypercubeᵀᴹ
1
Ich habe darüber nachgedacht und es auf SQL Server 2012 R2 ausgeführt - es wirft Fehler mit den Cmdlets Add-PSSnapin SqlServerCmdletSnapin100, aber es wird verarbeitet, solange Sie das Import-Module SQLPS vor dem Hauptteil des Skripts enthalten haben Prozess läuft. Technisch sollte dies eine bessere Fehlerprüfung haben, aber ich dachte mir, dass es eine gute schnelle Bearbeitung sein würde, um jemand anderem zu helfen, der möglicherweise nicht in der Lage ist, die Notwendigkeit für das Import-Modul SQLPS zu finden, wenn er sich in einem befindet neuere Version.
Chad Rexin
1
Danke vielmals. Kleines Problem. Die Namen der Robocopy-Dateien werden hier nicht in Anführungszeichen gesetzt. Wenn Sie Datenbanknamen mit Leerzeichen erstellt haben, funktioniert dies nicht richtig.
Tim Brigham
7
Sie können entweder die Modify File-Methode "Alter database" oder die Detach / Attach-Methode verwenden.
Hinweis: Beide erfordern einige Ausfallzeiten, die während des Wartungsfensters durchgeführt werden müssen.
Dies setzt voraus, dass Sie dieselbe Verzeichnisstruktur auf dem neuen Laufwerk haben, z. B. C: \ data \ und D: \ Data.
- Verwenden der Methode "Datenbank ändern" mit "Ändern" (bevorzugte Methode)
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
--- mit Old Detach / Attach-Methode (nicht bevorzugt, aber immer noch Leute verwenden es .. leider habe ich es vor kurzem auf einem Non-Prod-Server verwendet).
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
Die einzige Möglichkeit, mehrere DBs gleichzeitig zu erstellen, besteht darin, die Verschiebung für mehrere DBs gleichzeitig zu skripten.
ALTERDATABASE database_nameA SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameB SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameC SET OFFLINE WITHROLLBACK IMMEDIATE;-------
Hier können Sie die Dateien entweder manuell verschieben oder ein Skript dafür schreiben. Möglicherweise mit xp_cmdshell oder einem Tool. Wahrscheinlich ist es einfacher, die Dateien nur von Hand zu verschieben. Markieren Sie einige von ihnen und ziehen Sie sie per Drag & Drop.
-------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;
Wenn Sie die Datendatei und die Protokolldatei verschieben, müssen Sie natürlich sicherstellen, dass Sie den Teil DATEI ÄNDERN für jeden Teil ausführen.
Dieses Skript gibt eine Reihe von Anweisungen zurück, die Sie ausführen können.
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
Sie können entweder die Modify File-Methode "Alter database" oder die Detach / Attach-Methode verwenden.
Hinweis: Beide erfordern einige Ausfallzeiten, die während des Wartungsfensters durchgeführt werden müssen.
Dies setzt voraus, dass Sie dieselbe Verzeichnisstruktur auf dem neuen Laufwerk haben, z. B. C: \ data \ und D: \ Data.
- Verwenden der Methode "Datenbank ändern" mit "Ändern" (bevorzugte Methode)
--- mit Old Detach / Attach-Methode (nicht bevorzugt, aber immer noch Leute verwenden es .. leider habe ich es vor kurzem auf einem Non-Prod-Server verwendet).
quelle
Die einzige Möglichkeit, mehrere DBs gleichzeitig zu erstellen, besteht darin, die Verschiebung für mehrere DBs gleichzeitig zu skripten.
Hier können Sie die Dateien entweder manuell verschieben oder ein Skript dafür schreiben. Möglicherweise mit xp_cmdshell oder einem Tool. Wahrscheinlich ist es einfacher, die Dateien nur von Hand zu verschieben. Markieren Sie einige von ihnen und ziehen Sie sie per Drag & Drop.
Wenn Sie die Datendatei und die Protokolldatei verschieben, müssen Sie natürlich sicherstellen, dass Sie den Teil DATEI ÄNDERN für jeden Teil ausführen.
quelle
quelle
Dieses Skript gibt eine Reihe von Anweisungen zurück, die Sie ausführen können.
quelle