Eu uso o Powershell para esse tipo de trabalho. De fato, eu uso o Powershell para gerar o Powershell, porque tenho um script que percorre meus bancos de dados e gera meu script de movimentação final. Você precisará mover cada banco de dados, um de cada vez, mas isso ajudará pelo menos a criar 90% do trabalho.
#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
}}
A saída será um script FileMover.ps1 na pasta MyDocuments que se parece com isso:
O script move todos os arquivos, independentemente do local de origem, para o mesmo destino. Você precisará ajustar os caminhos de localização personalizados.
O script foi projetado para ser executado no servidor em que você precisa mover os arquivos (consulte todos os usos do localhost '). Substitua localhost pelo nome da sua instância se você executar remotamente.
O usuário que você executa como precisa acessar todos os caminhos de pasta envolvidos na movimentação, para atualizar as informações de nome de arquivo do servidor SQL e para mover os arquivos.
Eu uso o InvokeSQLCmd para execução offline / online devido à natureza descolada dos métodos .SetOffline () e .SetOnline. Eu achei isso mais confiável.
@ MikeFal Vi que você aprovou a edição. Como a pergunta está marcada com 2008R2, a adição não deve ser mais óbvia (em negrito ou algo assim)? (Não faço ideia, mas acho que talvez não funcione ou quebre algo em uma versão que não seja 2012).
ypercubeᵀᴹ
1
Pensei nisso e o executei no SQL Server 2012 R2 - gera erros com os cmdlets Add-PSSnapin SqlServerCmdletSnapin100, mas é processado desde que você tenha o SQLPS do módulo de importação incluído antes da parte principal do script processo é executado. Tecnicamente, isso deveria ter uma verificação de erro melhor, mas imaginei que seria uma boa edição rápida para ajudar alguém que talvez não consiga encontrar a necessidade do SQLPS do Módulo de Importação se eles estiverem em um versão mais recente.
Chad Rexin 17/03/16
1
Muito obrigado. Pequeno problema embora. Os nomes dos arquivos de robocópia não são citados aqui. Se você tiver criado nomes de bancos de dados com espaços, o usuário não funcionará corretamente.
Tim Brigham
7
Você pode usar os métodos Alterar arquivo, Modificar arquivo ou Desanexar / anexar.
Nota: Ambos exigirão algum tempo de inatividade, portanto, isso deve ser feito durante a janela de manutenção.
Isso pressupõe que você tenha a mesma estrutura de diretórios na nova unidade, por exemplo, C: \ data \ e D: \ Data.
- usando o banco de dados Alter com o método Modify (preferido)
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
--- usando o método Old Detach / Attach (não é o preferido, mas ainda assim as pessoas o usam .. infelizmente eu o usei recentemente em um servidor que não é um produto).
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
A única maneira que eu conheço de executar vários bancos de dados de uma só vez seria o script da movimentação de vários bancos de dados de uma só vez.
ALTERDATABASE database_nameA SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameB SET OFFLINE WITHROLLBACK IMMEDIATE;ALTERDATABASE database_nameC SET OFFLINE WITHROLLBACK IMMEDIATE;-------
Aqui você pode mover os arquivos manualmente ou escrever um script para fazer isso. Possivelmente usando xp_cmdshell ou alguma ferramenta. Provavelmente é mais fácil apenas mover os arquivos manualmente. Marque um monte deles e arraste e solte.
-------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;
Obviamente, se você mover o arquivo de dados e o arquivo de log, precisará fazer a parte MODIFY FILE para cada parte.
Este script retornará um lote de instruções que você pode executar.
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
Você pode usar os métodos Alterar arquivo, Modificar arquivo ou Desanexar / anexar.
Nota: Ambos exigirão algum tempo de inatividade, portanto, isso deve ser feito durante a janela de manutenção.
Isso pressupõe que você tenha a mesma estrutura de diretórios na nova unidade, por exemplo, C: \ data \ e D: \ Data.
- usando o banco de dados Alter com o método Modify (preferido)
--- usando o método Old Detach / Attach (não é o preferido, mas ainda assim as pessoas o usam .. infelizmente eu o usei recentemente em um servidor que não é um produto).
fonte
A única maneira que eu conheço de executar vários bancos de dados de uma só vez seria o script da movimentação de vários bancos de dados de uma só vez.
Aqui você pode mover os arquivos manualmente ou escrever um script para fazer isso. Possivelmente usando xp_cmdshell ou alguma ferramenta. Provavelmente é mais fácil apenas mover os arquivos manualmente. Marque um monte deles e arraste e solte.
Obviamente, se você mover o arquivo de dados e o arquivo de log, precisará fazer a parte MODIFY FILE para cada parte.
fonte
fonte
Este script retornará um lote de instruções que você pode executar.
fonte