Saya menggunakan Powershell untuk pekerjaan semacam ini. Bahkan, saya menggunakan Powershell untuk menghasilkan Powershell, karena saya memiliki skrip yang akan mengulangi basis data saya dan menghasilkan skrip langkah terakhir saya. Anda harus memindahkan setiap basis data satu per satu, tetapi ini setidaknya akan membantu Anda skrip 90% dari pekerjaan.
#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
}}
Outputnya akan berupa skrip FileMover.ps1 di folder MyDocuments Anda yang terlihat seperti ini:
Script memindahkan semua file, terlepas dari lokasi sumbernya, ke tujuan yang sama. Anda perlu mengubah jalur lokasi khusus.
Skrip ini dirancang untuk dijalankan di server tempat Anda perlu memindahkan file (lihat semua penggunaan localhost '). Ganti localhost dengan nama instance Anda jika Anda menjalankan ini dari jarak jauh.
Pengguna yang Anda jalankan ini membutuhkan akses ke semua jalur folder yang terlibat dalam gerakan, baik untuk memperbarui informasi nama file SQL server dan untuk memindahkan file.
Saya menggunakan InvokeSQLCmd untuk eksekusi Offline / Online karena sifat funky dari metode .SetOffline () dan .SetOnline. Saya menemukan ini lebih dapat diandalkan.
@ MikeFal Saya melihat Anda menyetujui hasil edit. Karena pertanyaan ditandai dengan 2008R2 bukankah penambahannya harus lebih jelas (cetak tebal atau apalah)? (Saya tidak tahu, tapi saya kira itu mungkin tidak berfungsi atau merusak sesuatu dalam versi selain 2012).
ypercubeᵀᴹ
1
Saya memikirkan hal itu dan saya sudah menjalankannya di SQL Server 2012 R2 - ia melempar kesalahan dengan Add-PSSnapin SqlServerCmdletSnapin100 cmdlet, tetapi melakukan proses selama Anda memiliki Impor-Modul SQLPS disertakan sebelum bagian utama dari skrip proses berjalan. Secara teknis ini seharusnya memiliki beberapa kesalahan pemeriksaan yang lebih baik di sekitar ini, tapi saya pikir untuk ini, bahwa itu akan menjadi edit cepat yang baik untuk membantu orang lain yang mungkin tidak dapat menemukan kebutuhan untuk Modul SQLPS Impor jika mereka menggunakan Versi terbaru.
Chad Rexin
1
Terima kasih banyak. Masalah kecil sekalipun. Nama file robocopy tidak dikutip di sini .. Jika Anda memiliki pengguna membuat nama database dengan spasi tidak berfungsi dengan benar.
Tim Brigham
7
Anda dapat menggunakan metode Alter database Modify File atau Detach / Attach.
Catatan: Keduanya akan membutuhkan waktu henti, jadi harus dilakukan selama jendela pemeliharaan.
Ini mengasumsikan bahwa Anda memiliki struktur direktori yang sama pada drive baru misalnya C: \ data \ dan D: \ Data.
- menggunakan database Alter dengan metode Modify (lebih disukai)
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
--- menggunakan metode Detach / Attach Lama (tidak disukai, tetapi masih orang menggunakannya .. sayangnya saya menggunakannya baru-baru ini di server 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
Satu-satunya cara yang saya tahu untuk melakukan banyak DB sekaligus adalah dengan skrip langkah untuk beberapa DB sekaligus.
ALTERDATABASE database_nameA SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameB SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameC SET OFFLINE WITHROLLBACK IMMEDIATE;-------
Di sini Anda dapat memindahkan file secara manual, atau menulis skrip untuk melakukannya. Mungkin menggunakan xp_cmdshell atau beberapa alat. Mungkin lebih mudah untuk hanya memindahkan file dengan tangan. Tandai banyak dari mereka, lalu seret dan lepas.
-------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;
Tentu saja jika Anda memindahkan file data dan file log Anda harus memastikan Anda melakukan bagian MODIFIKASI FILE untuk setiap bagian.
Script ini akan mengembalikan sejumlah pernyataan yang dapat Anda jalankan.
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
Anda dapat menggunakan metode Alter database Modify File atau Detach / Attach.
Catatan: Keduanya akan membutuhkan waktu henti, jadi harus dilakukan selama jendela pemeliharaan.
Ini mengasumsikan bahwa Anda memiliki struktur direktori yang sama pada drive baru misalnya C: \ data \ dan D: \ Data.
- menggunakan database Alter dengan metode Modify (lebih disukai)
--- menggunakan metode Detach / Attach Lama (tidak disukai, tetapi masih orang menggunakannya .. sayangnya saya menggunakannya baru-baru ini di server NON prod).
sumber
Satu-satunya cara yang saya tahu untuk melakukan banyak DB sekaligus adalah dengan skrip langkah untuk beberapa DB sekaligus.
Di sini Anda dapat memindahkan file secara manual, atau menulis skrip untuk melakukannya. Mungkin menggunakan xp_cmdshell atau beberapa alat. Mungkin lebih mudah untuk hanya memindahkan file dengan tangan. Tandai banyak dari mereka, lalu seret dan lepas.
Tentu saja jika Anda memindahkan file data dan file log Anda harus memastikan Anda melakukan bagian MODIFIKASI FILE untuk setiap bagian.
sumber
sumber
Script ini akan mengembalikan sejumlah pernyataan yang dapat Anda jalankan.
sumber