2 Server Arası Veri Tabanı Kopyalama

Merhaba,

2 sql server arası bir veya daha fazla veri tabanını taşıma ihtiyacı her zaman olmuştur. Tek tek backup alıp, diğer tarafa kopyaladıktan sonra tek tek restore etmemiz gerekirdi. Eğer kopyalanacak veri tabanı sayısı fazla ise bu işlem çok uzun ve can sıkıcı olabiliyor.

Bu işlemleri otomatize etmek için bir script geliştirdim. Parametre olarak verdiğimiz veri tabanlarını ilgili serverlar arası backup-restore yöntemi ile kopyalıyor.
Script size yeni bir script üretecek. Bu scripti management studio’da “SQLCMD” modunda çalıştırmanız gerekiyor.

Always On ya da mirroring kurulumu sırasında bu script oldukça işe yarayacaktır.

Parametre detaylarını script içine yazdım. Anlaşılmayan noktalar için yorum yazabilirsiniz.


SET NOCOUNT ON

DECLARE @CmdBackup NVARCHAR(MAX)
DECLARE @CmdRestore NVARCHAR(MAX)
DECLARE @CmdDelete NVARCHAR(MAX)
DECLARE @CmdShell NVARCHAR(MAX)
DECLARE @CmdMain NVARCHAR(MAX)
DECLARE @DbNames NVARCHAR(MAX)
DECLARE @DbTbl TABLE (dbname NVARCHAR(500))
DECLARE @DestinationServer NVARCHAR(250)
DECLARE @TargetServerName NVARCHAR(250)
DECLARE @FilePathForXCopy NVARCHAR(250)
DECLARE @BackupFilePath NVARCHAR(250)
DECLARE @NoRecovery BIT
DECLARE @replaceDB BIT
DECLARE @BackupWithLog BIT
DECLARE @DataFilesPath NVARCHAR(250)
DECLARE @LogFilePath NVARCHAR(250)
DECLARE @DeleteFilesAfterRestore BIT
DECLARE @guid NVARCHAR(50)

-- PARAMETERS -- ================================================================================== 

SET @DestinationServer = @@SERVERNAME -- Kopyalanacak veri tabanlarinin durdugu server.
SET @TargetServerName = '<TargetServer>' -- Hangi server'a kopyalanacak.
SET @DbNames = 'DB1, DB2' -- Hangi veri tabanlari kopyalansin? (,) virgul ile birden fazla isim yazabilirsin.
SET @BackupFilePath = '<BackupFilePath>' -- Backup nereye alinsin?
SET @FilePathForXCopy = '' -- Backup dosyalari nereye kopyalansin? NULL ya da bos olursa kopyalama yapilmaz direkt restore baslatilir.
SET @DataFilesPath = 'C:\Data' -- Hedef serverda data dosyalari nerede dursun?
SET @LogFilePath = 'C:\Log' -- Hedef serverda log dosyalari nerede dursun?
SET @NoRecovery = 0 -- 0: WITH RECOVERY, 1: WITH NORECOVERY
SET @replaceDB = 0 -- 1: Eger hedef serverda veri tabani mevcutsa üzerine yazar.
SET @BackupWithLog = 0 -- 1: Transaction Log Backup da alir.
SET @DeleteFilesAfterRestore = 1 -- Restore isleminden sonra tüm bak dosyalari silinir.

-- PARAMETERS -- ==================================================================================

SET @guid = REPLACE(NEWID(),'-','')

IF (@DbNames = '' OR @DbNames IS NULL)
BEGIN
    SET @DbNames = 'select name from sys.databases where database_id > 4 and state = 0 ' + (CASE WHEN (@BackupWithLog = 1) THEN 'and recovery_model <> 3' ELSE '' END)
   
END
ELSE
BEGIN
    SET @DbNames = 'select ''' +  REPLACE(REPLACE(@DbNames,' ',''), ',', ''' union select ''') + ''''
END

INSERT INTO @DbTbl
EXEC sp_executesql @dbnames

DELETE FROM @DbTbl
WHERE dbname in (select name from sys.databases where  database_id <= 4 or state <> 0 OR recovery_model = (CASE WHEN (@BackupWithLog = 1) THEN 3 ELSE -1 END))

Backup_Part:

IF((SELECT RIGHT(@BackupFilePath,1)) = '\')
	SET @BackupFilePath = LEFT(@BackupFilePath,LEN(@BackupFilePath)-1)

SELECT @CmdBackup = COALESCE(@CmdBackup + '','') + 'BACKUP DATABASE [' + name + '] TO DISK = N''' + @BackupFilePath +  '\' + name + '_' + @guid + '.bak'' WITH NO_CHECKSUM, COMPRESSION
GO
' + (CASE WHEN (@BackupWithLog = 1) THEN 'BACKUP LOG [' + name + '] TO DISK = N''' + @BackupFilePath +  '\' + name + '_' + @guid + '.trn'' WITH NO_CHECKSUM, COMPRESSION
GO
' ELSE '' END)
FROM sys.databases
WHERE name in (SELECT dbname FROM @DbTbl)

SET @CmdBackup = '--========== BACKUP ==========--
:connect ' + @DestinationServer + '

' + @CmdBackup

--select @CmdBackup

XCopy_Part:

IF (@FilePathForXCopy IS NULL OR @FilePathForXCopy = '')
BEGIN
	SET @FilePathForXCopy = @BackupFilePath
	GOTO Restore_Part
END

IF((SELECT RIGHT(@FilePathForXCopy,1)) = '\')
	SET @FilePathForXCopy = LEFT(@FilePathForXCopy,LEN(@FilePathForXCopy)-1)

SET @CmdShell = 'EXEC xp_cmdshell ''XCOPY ' + @BackupFilePath + '\*' + @guid + '*.* ' + @FilePathForXCopy + ' /S /Y'', NO_OUTPUT
EXEC xp_cmdshell ''DEL ' + @BackupFilePath + '\*' + @guid + '*.*  /F /Q /S'', NO_OUTPUT'

IF((SELECT value FROM sys.configurations WHERE name = 'xp_cmdshell') = 0)
BEGIN
    SET @CmdShell = 'EXEC sp_configure ''show advanced options'', 1
RECONFIGURE
EXEC sp_configure ''xp_cmdshell'', 1
RECONFIGURE

' + @CmdShell + '

--Disable xp_cmdshell
EXEC sp_configure ''show advanced options'', 1
RECONFIGURE
EXEC sp_configure ''xp_cmdshell'', 0
RECONFIGURE'
END

SET @CmdShell = '
--========== XCOPY ==========--
' + @CmdShell + '
GO'

--select @CmdShell

Restore_Part:

SELECT @CmdRestore = COALESCE(@CmdRestore + '','') + 
(CASE WHEN (file_id = 1) THEN 
'RESTORE DATABASE [' + DB_NAME(database_id) + '] FROM DISK = N''' + @FilePathForXCopy +  '\' + DB_NAME(database_id) + '_' + @guid + '.bak'' WITH FILE = 1,
MOVE N''' + name + ''' TO N''' + @DataFilesPath + '\' + REVERSE(LEFT(REVERSE(physical_name), charindex('\', REVERSE(physical_name)) - 1)) + ''', 
'
WHEN (file_id not in (1,2)) THEN 
'MOVE N''' + name + ''' TO N''' + @DataFilesPath + '\' + REVERSE(LEFT(REVERSE(physical_name), charindex('\', REVERSE(physical_name)) - 1)) + ''', 
'
WHEN (file_id = 2) THEN 
'MOVE N''' + name + ''' TO N''' + @LogFilePath + '\' + REVERSE(LEFT(REVERSE(physical_name), charindex('\', REVERSE(physical_name)) - 1)) + ''', 
' + (CASE WHEN (@replaceDB = 1) THEN 'REPLACE, ' ELSE '' END) + 'NORECOVERY, NOUNLOAD, STATS = 5
GO
' +  (CASE WHEN (@BackupWithLog = 1) THEN 'RESTORE LOG [' + DB_NAME(database_id) + '] FROM DISK = N''' + @FilePathForXCopy +  '\' + DB_NAME(database_id) + '_' + @guid + '.trn'' WITH FILE = 1, NORECOVERY, NOUNLOAD, STATS = 10
GO
' ELSE '' END)
ELSE '' END) + 
(CASE WHEN (@NoRecovery = 0 and file_id = 2) THEN 'RESTORE DATABASE [' + DB_NAME(database_id) + '] WITH RECOVERY
GO
' ELSE '' END)

FROM sys.master_files
WHERE DB_NAME(database_id) IN (SELECT dbname FROM @DbTbl)
ORDER BY DB_NAME(database_id) ASC, [type] ASC, file_id ASC

SET @CmdRestore = '

--========== RESTORE ==========--
:connect ' + @TargetServerName + '

' + @CmdRestore

--select @CmdRestore

Delete_Part:
IF @DeleteFilesAfterRestore = 0
	GOTO Script_Part

SELECT @CmdDelete = COALESCE(@CmdDelete + '','--========== DELETE ==========--') + '
EXEC xp_delete_file 0, N''' + @FilePathForXCopy +  '\' + name + '_' + @guid + '.bak'', ''Bak'',''Oct 01 2020  1:00PM'', 0
GO'

FROM sys.databases
WHERE name in (SELECT dbname FROM @DbTbl)


Script_Part:
SET @CmdMain = '/*** EXECUTE IN SQLCMD MODE ***/

' + @CmdBackup + ISNULL(@CmdShell,'') + @CmdRestore + ISNULL(@CmdDelete,'')

SELECT @CmdMain
GO

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s