Я использую Powershell для такой работы. Фактически, я использую Powershell для генерации Powershell, потому что у меня есть скрипт, который будет циклически проходить по моим базам данных и генерировать мой последний скрипт перемещения. Вам придется перемещать каждую базу данных по одной за раз, но это, по крайней мере, поможет вам написать 90% работы.
#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
}}
Результатом будет скрипт FileMover.ps1 в папке MyDocuments, который выглядит примерно так:
Сценарий перемещает все файлы, независимо от их исходного местоположения, в одно и то же место назначения. Вам нужно будет настроить собственные пути расположения.
Скрипт предназначен для запуска на сервере, на котором вам нужно переместить файлы (см. Все случаи использования localhost '). Замените localhost на имя вашего экземпляра, если вы запускаете это удаленно.
Пользователю, которого вы запускаете, требуется доступ ко всем путям папок, участвующим в перемещении, как для обновления информации об имени файла сервера SQL, так и для перемещения файлов.
Я использую InvokeSQLCmd для выполнения в автономном / онлайн-режиме из-за необычной природы методов .SetOffline () и .SetOnline. Я нашел это, чтобы быть более надежным.
@MikeFal Я видел, как вы одобрили редактирование. Поскольку вопрос помечен 2008R2, не должно ли дополнение быть более очевидным (жирным шрифтом или чем-то еще)? (Я понятия не имею, но я предполагаю, что это может не сработать или сломать что-то в версии, отличной от 2012).
ypercubeᵀᴹ
1
Я подумал об этом и запустил его на SQL Server 2012 R2 - он выдает ошибки с помощью командлетов Add-PSSnapin SqlServerCmdletSnapin100, но обрабатывает, пока у вас есть SQL-модуль импорта, включенный перед основной частью скрипта процесс запускается. Технически это должно иметь некоторую лучшую проверку ошибок вокруг этого, но я решил для этого, что это было бы хорошим быстрым редактированием, чтобы помочь кому-то, кто, возможно, не смог найти необходимость в SQLPS-модуле импорта, если они находятся на более новая версия.
Чад Рексин
1
Благодаря тонну. Небольшая проблема, хотя. Имена файлов robocopy здесь не приводятся. Если у вас есть созданные пользователем базы данных с пробелами, это не совсем правильно работает.
Тим Бригам
7
Вы можете использовать либо Изменить базу данных Изменить файл или Отсоединить / Присоединить методы.
Примечание: оба требуют некоторого времени простоя, поэтому это должно быть сделано во время технического обслуживания.
Это предполагает, что у вас есть та же структура каталогов на новом диске, например, C: \ data \ и D: \ Data.
- использование базы данных Alter с методом Modify (предпочтительнее)
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
--- используя старый способ отсоединения / присоединения (не рекомендуется, но все же люди его используют .. к сожалению, я недавно использовал его на сервере 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
Единственный способ, который я знаю, чтобы сделать несколько БД одновременно, это написать сценарий перемещения для нескольких БД одновременно.
ALTERDATABASE database_nameA SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameB SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameC SET OFFLINE WITHROLLBACK IMMEDIATE;-------
Здесь вы можете либо переместить файлы вручную, либо написать скрипт для этого. Возможно, используя xp_cmdshell или какой-либо инструмент. Вероятно, проще просто переместить файлы вручную. Отметьте их несколько, затем перетащите.
-------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;
Конечно, если вы перемещаете файл данных и файл журнала, вы должны убедиться, что вы выполняете часть MODIFY FILE для каждой части.
Этот скрипт вернет пакет операторов, которые вы можете запустить.
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
Вы можете использовать либо Изменить базу данных Изменить файл или Отсоединить / Присоединить методы.
Примечание: оба требуют некоторого времени простоя, поэтому это должно быть сделано во время технического обслуживания.
Это предполагает, что у вас есть та же структура каталогов на новом диске, например, C: \ data \ и D: \ Data.
- использование базы данных Alter с методом Modify (предпочтительнее)
--- используя старый способ отсоединения / присоединения (не рекомендуется, но все же люди его используют .. к сожалению, я недавно использовал его на сервере NON Prod).
источник
Единственный способ, который я знаю, чтобы сделать несколько БД одновременно, это написать сценарий перемещения для нескольких БД одновременно.
Здесь вы можете либо переместить файлы вручную, либо написать скрипт для этого. Возможно, используя xp_cmdshell или какой-либо инструмент. Вероятно, проще просто переместить файлы вручную. Отметьте их несколько, затем перетащите.
Конечно, если вы перемещаете файл данных и файл журнала, вы должны убедиться, что вы выполняете часть MODIFY FILE для каждой части.
источник
источник
Этот скрипт вернет пакет операторов, которые вы можете запустить.
источник