在项目实施过程中,有时候会遇到大批量数据库(上百个)同时迁移的问题,如果采用常规的备份还原的方式会消耗非常多的时间,对业务会造成非常大的影响,生产环境下业务很难接受这种方式,所以我们采取镜像的方式来做迁移,即提前搭建镜像,在迁移的时候进行故障转移,然后断开镜像连接,由于数据库太多,我们会通过脚本进行批量操作。
首先需要建立所有数据库的源服务器到目标数据库的镜像关系,由于数据库太多,这里我们也使用脚本进行批量备份和还原:
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‘,‘DB100‘
))a
where @total=a.sequence;
set @date=replace(convert(varchar,getdate(),23),‘-‘,‘‘)
set @path=‘Y:\Backup\‘[email protected]+‘_‘[email protected]+‘.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 @[email protected]
end
备份日志:
Declare @total int
select @total=count(name) from sys.databases where name in
(
‘DB1‘,‘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‘,‘DB100‘
))a
where @total=a.sequence;
set @date=replace(convert(varchar,‘‘)
set @path=‘Y:\Backup\‘[email protected]+‘_‘[email protected]+‘_Log.bak‘;
print @path
set @sql01=‘BACKUP LOG ‘+quotename(@dbname,NAME=‘+quotename(‘Log Backup‘,STATS = 10‘
print @sql01
exec (@sql01);
set @[email protected]
end
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‘,‘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‘,‘‘)
set @path1=‘Y:\Backup\‘[email protected]+‘_‘[email protected]+‘.bak‘
set @path2=‘W:\sqlServer\Data\‘[email protected]+‘.mdf‘
set @path3=‘W:\sqlServer\Data\‘[email protected]+‘.ndf‘
set @path4=‘Y:\sqlServer\Log\‘[email protected]+‘.ldf‘
create table #Logicalname
(LogicalName nvarchar(128)
,PhysicalName nvarchar(260)
,Type char(1)
,FileGroupName nvarchar(128)
,Size numeric(20,0)
,MaxSize numeric(20,FileID bigint
,CreateLSN numeric(25,DropLSN numeric(25,0) NULL
,UniqueID uniqueidentifier
,ReadOnlyLSN numeric(25,ReadWriteLSN numeric(25,BackupSizeInBytes bigint
,SourceBlockSize int
,FileGroupID int
,LogGroupGUID uniqueidentifier
,DifferentialBaseLSN numeric(25,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,STATS = 10‘
print @sql01
exec (@sql01);
set @[email protected]
drop table #Logicalname
end
还原日志
Declare @total int
select @total=count(name) from sys.databases where name in
(
‘DB1‘,‘‘)
set @path=‘Y:\Backup\‘[email protected]+‘_‘[email protected]+‘_Log.bak‘;
print @path
set @sql01=‘RESTORE LOG ‘+quotename(@dbname,‘‘)+‘ from disk=‘+quotename(@path,‘‘‘‘)+‘ with FILE=1,STATS = 10‘
print @sql01
exec (@sql01);
set @[email protected]
end
3. 创建镜像
在目标服务器上进行partner配置:
select @total=count(name) from sys.databases where name in
(
‘DB1‘,‘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‘,‘DB100‘
))a
where @total=a.sequence;
set @sql01=‘ALTER DATABASE ‘+quotename(@dbname,‘‘)+‘ set PARTNER=‘+quotename(‘TCP://SourceServer.domain:5022‘,‘‘‘‘)
print @sql01
exec (@sql01);
set @ [email protected]
end
select @total=count(name) from sys.databases where name in
(
‘DB1‘,‘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‘,‘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 @ [email protected]
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. 迁移时,先更改镜像状态为安全模式(只有在安全模式下,镜像才能执行故障转移):
(
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‘reportserver$KABA_MAIN‘
)
) a
where @Total=a.Sequence;
set @sql=
‘use master;‘+
‘Alter database ‘+quotename(@Userdbname,‘‘)+‘ set partner failover
‘;
print @sql;
exec (@sql);
set @ [email protected]
end
where mirroring_guid is not NULL
select @total=count(name) from sys.databases where name in
(
‘DB1‘,‘DB100‘
))a
where @total=a.sequence;
set @sql01=
‘use master;‘+
‘Alter database ‘+quotename(@dbname,‘‘)+‘ set partner off
‘;
print @sql01
exec (@sql01);
set @ [email protected]
end
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‘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 @ [email protected]
end
Create table #Orphan_User
(
UserName varchar(100),
UserID varchar(500)
)
select @Total=count(*) from sys.databases where
-- name not in
--(
--N‘master‘,
--N‘DWConfiguration‘,
--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‘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‘,‘‘‘‘)
;
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;