Używam Powershell do tego rodzaju pracy. W rzeczywistości używam Powershell do generowania Powershell, ponieważ mam skrypt, który będzie przeglądał moje bazy danych i generował mój ostatni skrypt przeniesienia. Każdą bazę danych będziesz musiał przenieść pojedynczo, ale to przynajmniej pomoże ci napisać 90% pracy.
#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}}
Wynikiem będzie skrypt FileMover.ps1 w folderze MyDocuments, który wygląda mniej więcej tak:
Skrypt przenosi wszystkie pliki, bez względu na ich lokalizację źródłową, do tego samego miejsca docelowego. Trzeba będzie dostosować niestandardowe ścieżki lokalizacji.
Skrypt został zaprojektowany do działania na serwerze, na którym należy przenieść pliki (zobacz wszystkie zastosowania localhost '). Zastąp localhost nazwą swojej instancji, jeśli uruchomisz to zdalnie.
Użytkownik, który uruchamiasz go, potrzebuje dostępu do wszystkich ścieżek folderów biorących udział w przenoszeniu, zarówno w celu aktualizacji informacji o nazwie pliku SQL Server, jak i przenoszenia plików.
Korzystam z InvokeSQLCmd do wykonywania offline / online ze względu na funky charakter metod .SetOffline () i .SetOnline. Przekonałem się, że jest to bardziej niezawodne.
@MikeFal Widziałem, że zatwierdziłeś zmianę. Skoro pytanie jest oznaczone jako 2008R2, to czy dodanie nie powinno być bardziej oczywiste (pogrubienie czy coś takiego)? (Nie mam pojęcia, ale zgaduję, że może nie działać lub popsuć coś w wersji innej niż 2012).
ypercubeᵀᴹ
1
Pomyślałem o tym i uruchomiłem go na SQL Server 2012 R2 - generuje błędy w apletach cmdlet Add-PSSnapin SqlServerCmdletSnapin100, ale przetwarza tak długo, jak długo masz SQL Server modułu importu przed główną częścią skryptu proces działa. Technicznie powinno to mieć lepsze sprawdzanie błędów wokół tego, ale doszedłem do tego, że byłoby to dobre szybkie edytowanie, aby pomóc komuś innemu, kto być może nie był w stanie znaleźć zapotrzebowania na moduł importu SQLPS, jeśli są na nowsza wersja.
Chad Rexin,
1
Wielkie dzięki. Mały problem. Nazwy plików robocopy nie są tutaj cytowane. Jeśli masz nazwy baz danych utworzone przez użytkownika ze spacjami, nie działa to całkiem dobrze.
Tim Brigham,
7
Możesz użyć opcji Zmień bazę danych Zmień plik lub Odłącz / Dołącz.
Uwaga: Oba wymagają pewnego czasu przestoju, więc należy to zrobić w oknie konserwacji.
Zakłada się, że masz taką samą strukturę katalogów na nowym dysku, np. C: \ data \ i D: \ Data.
- korzystanie z bazy danych Alter z metodą Modyfikuj (preferowana)
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
--- przy użyciu metody Old Detach / Attach (nie preferowane, ale ludzie nadal go używają .. niestety ostatnio używałem go na serwerze 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
Jedynym sposobem, w jaki wiem, aby robić wiele baz danych na raz, byłoby wykonanie skryptu dla wielu baz danych jednocześnie.
ALTERDATABASE database_nameA SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameB SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameC SET OFFLINE WITHROLLBACK IMMEDIATE;-------
Tutaj możesz przenieść pliki ręcznie lub napisać skrypt, aby to zrobić. Prawdopodobnie za pomocą xp_cmdshell lub innego narzędzia. Prawdopodobnie łatwiej jest po prostu ręcznie przenieść pliki. Zaznacz kilka z nich, a następnie przeciągnij i upuść.
-------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;
Oczywiście, jeśli przenosisz plik danych i plik dziennika, musisz upewnić się, że wykonałeś część MODYFIKUJ PLIK dla każdej części.
Ten skrypt zwróci zestaw instrukcji, które możesz uruchomić.
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
Możesz użyć opcji Zmień bazę danych Zmień plik lub Odłącz / Dołącz.
Uwaga: Oba wymagają pewnego czasu przestoju, więc należy to zrobić w oknie konserwacji.
Zakłada się, że masz taką samą strukturę katalogów na nowym dysku, np. C: \ data \ i D: \ Data.
- korzystanie z bazy danych Alter z metodą Modyfikuj (preferowana)
--- przy użyciu metody Old Detach / Attach (nie preferowane, ale ludzie nadal go używają .. niestety ostatnio używałem go na serwerze NON prod).
źródło
Jedynym sposobem, w jaki wiem, aby robić wiele baz danych na raz, byłoby wykonanie skryptu dla wielu baz danych jednocześnie.
Tutaj możesz przenieść pliki ręcznie lub napisać skrypt, aby to zrobić. Prawdopodobnie za pomocą xp_cmdshell lub innego narzędzia. Prawdopodobnie łatwiej jest po prostu ręcznie przenieść pliki. Zaznacz kilka z nich, a następnie przeciągnij i upuść.
Oczywiście, jeśli przenosisz plik danych i plik dziennika, musisz upewnić się, że wykonałeś część MODYFIKUJ PLIK dla każdej części.
źródło
źródło
Ten skrypt zwróci zestaw instrukcji, które możesz uruchomić.
źródło