在項目實施過程中,有時候會遇到大批量數據庫(上百個)同時遷移的問題,如果采用常規的備份還原的方式會消耗非常多的時間,對業務會造成非常大的影響,生產環境下業務很難接受這種方式,所以我們采取鏡像的方式來做遷移,即提前搭建鏡像,在遷移的時候進行故障轉移,然后斷開鏡像連接,由於數據庫太多,我們會通過腳本進行批量操作。
首先需要建立所有數據庫的源服務器到目標數據庫的鏡像關系,由於數據庫太多,這里我們也使用腳本進行批量備份和還原:
1. 批量備份指定的數據庫和日志(備份數據庫時間較長,故備份日志):
Declare @total int
select @total=count(name) from sys.databases where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path varchar(1000)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from sys.databases
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @date=replace(convert(varchar,getdate(),23),'-','')
set @path='Y:\Backup\'+@DBname+'_'+@date+'.bak';
print @path
set @sql01='BACKUP DATABASE '+quotename(@DBname,'[]')+' TO DISK='+quotename(@path,'''')+' WITH NOFORMAT,NOINIT,NAME='+quotename('Full Database Backup','''')+',SKIP,NOREWIND,NOUNLOAD,STATS = 10'
print @sql01
exec (@sql01);
set @total=@total-1
end
備份日志:
Declare @total int
select @total=count(name) from sys.databases where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path varchar(1000)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from sys.databases
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @date=replace(convert(varchar,getdate(),23),'-','')
set @path='Y:\Backup\'+@DBname+'_'+@date+'_Log.bak';
print @path
set @sql01='BACKUP LOG '+quotename(@DBname,'[]')+' TO DISK='+quotename(@path,'''')+' WITH NOFORMAT,NOINIT,NAME='+quotename('Log Backup','''')+',SKIP,NOREWIND,NOUNLOAD,STATS = 10'
print @sql01
exec (@sql01);
set @total=@total-1
end
Copy數據庫備份文件和日志備份文件到目標服務器
2. 自動檢查邏輯名(用RESTORE FILELISTONLY命令從備份文件中讀取數據庫的信息,本例中有三個邏輯文件)后進行還原:
Create table #database
(name varchar(100))
insert into #database
values
('DB1')
,('DB2')
,('DB3')
,('DB4')
,('DB100')
--drop table #database
--select * from #database
Declare @total int
select @total=count(name) from #database where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path1 varchar(1000)
Declare @path2 varchar(1000)
Declare @path3 varchar(1000)
Declare @path4 varchar(1000)
Declare @Mdfname varchar(50)
Declare @Ndfname varchar(50)
Declare @Logname varchar(50)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from #database
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @date=replace(convert(varchar,getdate(),23),'-','')
set @path1='Y:\Backup\'+@DBname+'_'+@date+'.bak'
set @path2='W:\SQLServer\Data\'+@DBname+'.mdf'
set @path3='W:\SQLServer\Data\'+@DBname+'.ndf'
set @path4='Y:\SQLServer\Log\'+@DBname+'.ldf'
create table #Logicalname
(LogicalName nvarchar(128)
,PhysicalName nvarchar(260)
,Type char(1)
,FileGroupName nvarchar(128)
,Size numeric(20,0)
,MaxSize numeric(20,0)
,FileID bigint
,CreateLSN numeric(25,0)
,DropLSN numeric(25,0) NULL
,UniqueID uniqueidentifier
,ReadOnlyLSN numeric(25,0)
,ReadWriteLSN numeric(25,0)
,BackupSizeInBytes bigint
,SourceBlockSize int
,FileGroupID int
,LogGroupGUID uniqueidentifier
,DifferentialBaseLSN numeric(25,0)
,DifferentialBaseGUID uniqueidentifier
,IsReadOnly bit
,IsPresent bit
,TDEThumbprint varbinary(32)
)
Declare @restore varchar(1000)
set @restore='RESTORE FILELISTONLY from disk='+QUOTENAME(@path1,'''')
print @restore
exec (@restore)
insert into #Logicalname exec (@restore)
--select * from #Logicalname
select @Mdfname=LogicalName from #Logicalname where Fileid=1
select @Ndfname=LogicalName from #Logicalname where FileID=3
select @Logname=LogicalName from #Logicalname where FileID=2
set @sql01='RESTORE DATABASE '+quotename(@DBname,'[]')+' from disk='+quotename(@path1,'''')+' WITH FILE = 1,MOVE '+quotename(@Mdfname,'''')+' to '+
quotename(@path2,'''')+',move '+quotename(@Ndfname,'''')+' to '+quotename(@path3,'''')+
',move '+quotename(@Logname,'''')+' to '+quotename(@path4,'''')+',NORECOVERY,NOUNLOAD,STATS = 10'
print @sql01
exec (@sql01);
set @total=@total-1
drop table #Logicalname
end
還原日志
Declare @total int
select @total=count(name) from sys.databases where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path varchar(1000)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from sys.databases
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @date=replace(convert(varchar,getdate(),23),'-','')
set @path='Y:\Backup\'+@DBname+'_'+@date+'_Log.bak';
print @path
set @sql01='RESTORE LOG '+quotename(@DBname,'')+' from disk='+quotename(@path,'''')+' with FILE=1,NORECOVERY,NOUNLOAD,STATS = 10'
print @sql01
exec (@sql01);
set @total=@total-1
end
3. 創建鏡像
在目標服務器上進行partner配置:
select @total=count(name) from sys.databases where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path varchar(1000)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from sys.databases
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @sql01='ALTER DATABASE '+quotename(@DBname,'')+' set PARTNER='+quotename('TCP://SourceServer.domain:5022','''')
print @sql01
exec (@sql01);
set @total=@total-1
end
select @total=count(name) from sys.databases where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path varchar(1000)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from sys.databases
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @sql01='ALTER DATABASE '+quotename(@DBname,'')+' set PARTNER='+quotename('TCP://DestinationServer.Domain:5022','''');
set @sql02='ALTER DATABASE '+quotename(@DBname,'')+' SET PARTNER SAFETY OFF';
print @sql01
print @sql02
exec (@sql01);
exec (@sql02);
set @total=@total-1
end
select N'EXEC sp_addsrvrolemember N''' +sp.name+ ''' ,N''' + rsp.name+''' '
FROM sys.server_principals sp
LEFT JOIN sys.server_role_members srm ON sp.principal_id=srm.member_principal_id
LEFT JOIN sys.server_principals rsp ON srm.role_principal_id=rsp.principal_id
where rsp.name is not null
遷移Job:右鍵Job, 按’F7’, 多選了之后右鍵,點擊create to new window,然后copy整個窗口的內容到目的服務器執行
5. 遷移時,先更改鏡像狀態為安全模式(只有在安全模式下,鏡像才能執行故障轉移):
Declare @sql nvarchar(2000)
Declare @Total int
(
N'master', N'model', N'msdb', N'tempdb', N'distribution', N'DWDiagnostics',
N'DWConfiguration', N'DWQueue', N'resource',N'ReportServer',N'ReportServerTempDB',
N'ReportServer$KABA_MAINTempDB',N'ReportServer$KABA_MAIN'
)
begin
select @UserDBname=a.name from (
Select name, row_number() over(order by name) Sequence from sys.databases
where name not in
(
N'master', N'model', N'msdb', N'tempdb', N'distribution', N'DWDiagnostics',
N'DWConfiguration', N'DWQueue', N'resource',N'ReportServer',N'ReportServerTempDB',
N'ReportServer$KABA_MAINTempDB',N'ReportServer$KABA_MAIN'
)
) a
where @Total=a.Sequence;
set @sql=
'use master;'+
'Alter database '+quotename(@UserDBname,'')+' set partner failover
';
print @sql;
exec (@sql);
set @Total=@Total-1
end
where mirroring_guid is not NULL
select @total=count(name) from sys.databases where name in
(
'DB1','DB2','DB3','DB4','DB100'
)
while @total<>0
begin
Declare @DBname varchar(1000)
Declare @sql01 varchar(2000)
Declare @sql02 varchar(2000)
Declare @path varchar(1000)
Declare @date varchar(50)
select @DBname=a.name from
(select name,row_number()over(order by name) sequence from sys.databases
where name in
(
'DB1','DB2','DB3','DB4','DB100'
))a
where @total=a.sequence;
set @sql01=
'use master;'+
'Alter database '+quotename(@DBname,'')+' set partner off
';
print @sql01
exec (@sql01);
set @total=@total-1
end
Declare @sql nvarchar(2000)
Declare @Total int
(
N'master', N'model', N'msdb', N'tempdb', N'distribution', N'DWDiagnostics',
N'DWConfiguration', N'DWQueue', N'resource',N'ReportServer',N'ReportServerTempDB',
N'ReportServer$KABA_MAINTempDB',N'ReportServer$KABA_MAIN'
)
begin
select @UserDBname=a.name from (
Select name, row_number() over(order by name) Sequence from sys.databases
where name not in
(
N'master', N'model', N'msdb', N'tempdb', N'distribution', N'DWDiagnostics',
N'DWConfiguration', N'DWQueue', N'resource',N'ReportServer',N'ReportServerTempDB',
N'ReportServer$KABA_MAINTempDB',N'ReportServer$KABA_MAIN'
)
) a
where @Total=a.Sequence;
set @sql=
'use '+quotename(@UserDBname,'')+'; select DB_Name() as DBName; '+
'exec sp_change_users_login @Action='+quotename('Report','''')
;
print @sql;
exec (@sql);
set @Total=@Total-1
end
Declare @sql nvarchar(2000)
Declare @Total int
Create table #Orphan_User
(
UserName varchar(100),
UserID varchar(500)
)
select @Total=count(*) from sys.databases where
-- name not in
--(
--N'master', N'model', N'msdb', N'tempdb', N'distribution', N'DWDiagnostics',
--N'DWConfiguration', N'DWQueue', N'resource',N'ReportServer',N'ReportServerTempDB',
--N'ReportServer$KABA_MAINTempDB',N'ReportServer$KABA_MAIN'
--)
--and
name in (N'ZRBT_01077')
begin
select @UserDBname=a.name from (
Select name, row_number() over(order by name) Sequence from sys.databases
where
-- name not in
--(
--N'master', N'model', N'msdb', N'tempdb', N'distribution', N'DWDiagnostics',
--N'DWConfiguration', N'DWQueue', N'resource',N'ReportServer',N'ReportServerTempDB',
--N'ReportServer$KABA_MAINTempDB',N'ReportServer$KABA_MAIN'
--)
--and
name in (N'ZRBT_01077')
) a
where @Total=a.Sequence;
'use '+quotename(@UserDBname,'')+
';insert into #Orphan_User exec sp_change_users_login @Action='+quotename('Report','''')
;
exec (@sql);
select * from #Orphan_User
Declare DropUser cursor
for
select UserName from #Orphan_User;
open DropUser;
fetch next from DropUser into @UserName;
while @@FETCH_STATUS=0
begin
Declare @DropUsersql varchar(1000)
set @DropUsersql=
'use '+quotename(@UserDBname,'')+';
DROP SCHEMA'+quotename(@UserName,'[]')+';
DROP USER'+ quotename(@UserName,'[]');
print (@DropUsersql)
exec (@DropUsersql)
fetch next from DropUser into @UserName;
end
close DropUser;
deallocate DropUser;
set @Total=@Total-1
end
