0

Çoğu zaman test ortamlarımızı birebir production’ın aynısı olarak tasarlama ihtiyacı duyarız. Test ortamımızda Production sunucumuzda bulunan disk partition yapılarının, drive letter’larının bile aynı olmasını isteriz.

Eğer bu şekilde birebir şekilde bir yapı kurmak istersek ve dataların güncelliği de bizim için önemliyse production üzerinden scheduled olarak bir gün önceki full backup’ları restore etme ihtiyacı duyarız. Bu tarz data aktarımları için backup file’larının test ortamına kopyalanmasını genelde ya kendi yazdığımız bir uygulama, script veya 3rd party tool’lar ile gerçekleştiririz. Test ortamı üzerine backup’ları aldıktan sonra aynı partition yapısını koruyarak restore edilecek lokasyonlarında bir önceki backup’ta nasıl restore edildiyse aynı şekilde korumak isteyebiliriz. Bazı kurumlarda database’lerin file’ları çok sıklıkla arttırılıp, lokasyonlarında da değişiklikler olabiliyor. Bunun için yazmış olduğum bir script var. Bu yazımda bunu paylaşmak istiyorum. Öncelikle script’te neler yapabiliyoruz onu görelim.

 

RESTORE FILELISTONLY ve RESTORE HEADERONLY

Backup file’ları oluşturulurken database’in bir nevi signature’ı bu file’lara yazılır. Bu bilgilere örnek olarak backup’ı alan user’dan MDF ve LDF dosyalarının detaylı bilgileri verilebilir. FILELISTONLY ve HEADERONLY kullanımları aşağıdaki gibidir;

 

RESTORE FILELISTONLY FROM DISK = 'D:\AdventureWorks2012.bak'


 

 

RESTORE HEADERONLY FROM DISK = 'D:\AdventureWorks2012.bak'

 

 

Peki bu bahsetmiş olduğumuz FILELISTONLY ve HEADERONLY özelliklerini script’imiz içerisinde nasıl kullanabiliriz. Burada bizim için önemli olan FILELISTONLY’den çıkarttığımız LogicalName, PhysicalName ve HEADERONLY’den gelen DatabaseName dir. Bu bilgileri script’imiz içerisinde kullanarak data’nın veya log’un en son lokasyonunu, mantıksal ismini ve database ismini rahatlıkla kullanabiliriz.

Aşağıda yazmış olduğum Stored Procedure’da bu özellikleri kullanmak için ilk olarak FILELISTONLY ve HEADERONLY’yi sanal tabloya alıyorum. Sanal tabloya aktarmış olduğum bu özellikleri RESTORE DATABASE ifadem içerisinde kullanıyorum. Database’lerimde birden fazla NDF olduğundan dolayı XML olarak lokasyon ve isimleri alıp tek tek NDF’leri Restore ifademe ekliyorum. İlgili SP’nin tam hali aşağıdaki gibidir;

CREATE PROCEDURE [dbo].[sp_RestoreDatabase] @DatabasePath VARCHAR(250)
AS

DECLARE @LogicalDataName NVARCHAR(128)
DECLARE @PhysicalDataName NVARCHAR(260)
DECLARE @LogicalLogName NVARCHAR(128)
DECLARE @PhysicalLogName NVARCHAR(260)
DECLARE @DatabaseName NVARCHAR(128)
DECLARE @RestoreSQL NVARCHAR(MAX)

DECLARE @FileListTable TABLE
(
    [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),
    [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 @FileHeaderOnly TABLE
(
    [BackupName]                NVARCHAR(128),
    [BackupDescription]         NVARCHAR(255), 
    [BackupType]                SMALLINT, 
    [ExpirationDate]            DATETIME,
    [Compressed]                TINYINT,
    [Position]                  SMALLINT,
    [DeviceType]                TINYINT,
    [UserName]                  NVARCHAR(128),
    [ServerName]                NVARCHAR(128),
    [DatabaseName]              NVARCHAR(128),
    [DatabaseVersion]           INT,
    [DatabaseCreationDate]      DATETIME,
    [BackupSize]                NUMERIC(20,0),
    [FirstLSN]                  NUMERIC(25,0),
    [LastLSN]                   NUMERIC(25,0),
    [CheckpointLSN]             NUMERIC(25,0),
    [DatabaseBackupLSN]         NUMERIC(25,0),
    [BackupStartDate]           DATETIME,
    [BackupFinishDate]          DATETIME,
    [SortOrder]                 SMALLINT,
    [CodePage]                  SMALLINT,
    [UnicodeLocaleId]           INT,
    [UnicodeComparisonStyle]    INT,
    [CompatibilityLevel]        TINYINT,
    [SoftwareVendorId]          INT,
    [SoftwareVersionMajor]      INT,
    [SoftwareVersionMinor]      INT,
    [SoftwareVersionBuild]      INT,
    [MachineName]               NVARCHAR(128),
    [Flags]                     INT,
    [BindingID]                 UNIQUEIDENTIFIER,
    [RecoveryForkID]            UNIQUEIDENTIFIER,
    [Collation]                 NVARCHAR(128),
    [FamilyGUID]                UNIQUEIDENTIFIER,
    [HasBulkLoggedData]         BIT,
    [IsSnapshot]                BIT,
    [IsReadOnly]                BIT,
    [IsSingleUser]              BIT,
    [HasBackupChecksums]        BIT,
    [IsDamaged]                 BIT,
    [BeginsLogChain]            BIT,
    [HasIncompleteMetaData]     BIT,
    [IsForceOffline]            BIT,
    [IsCopyOnly]                BIT,
    [FirstRecoveryForkID]       UNIQUEIDENTIFIER,
    [ForkPointLSN]              NUMERIC(25,0) NULL,
    [RecoveryModel]             NVARCHAR(60),
    [DifferentialBaseLSN]       NUMERIC(25,0) NULL,
    [DifferentialBaseGUID]      UNIQUEIDENTIFIER,
    [BackupTypeDescription]     NVARCHAR(60),
    [BackupSetGUID]             UNIQUEIDENTIFIER NULL,
    [CompressedBackupSize]      BIT
)

INSERT INTO @FileListTable  EXEC('RESTORE FILELISTONLY FROM DISK = ''' + @DatabasePath + '''')
INSERT INTO @FileHeaderOnly EXEC('RESTORE HEADERONLY FROM DISK = ''' + @DatabasePath + '''')

SELECT @LogicalDataName = [LogicalName], @PhysicalDataName = [PhysicalName] FROM @FileListTable WHERE [Type] = 'D'
SELECT @LogicalLogName = [LogicalName], @PhysicalLogName = [PhysicalName] FROM @FileListTable WHERE [Type] = 'L'
SELECT @DatabaseName = [DatabaseName] FROM @FileHeaderOnly

SELECT @LogicalDataName, @PhysicalDataName
SELECT @LogicalLogName, @PhysicalLogName

SELECT @RestoreSQL = '
RESTORE DATABASE ' + @DatabaseName + ' 
FROM DISK = N''' + @DatabasePath + ''' WITH  FILE = 1, 
' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(STUFF((SELECT ' MOVE N''' + LogicalName + ''' TO N''' +  PhysicalName + ''',
' FROM @FileListTable FOR XML PATH('')), 1, 1, '<'), '</DATA><DATA>', ', '), '</DATA>', ''), '<DATA>', ''), '<MOVE', ' MOVE'), '&#x0D;', '')
+ 'NOUNLOAD, REPLACE'

IF @DatabaseName NOT IN ('master', 'model', 'msdb', 'tempdb')
 BEGIN
     EXECUTE sp_executesql @RestoreSQL
 END

 

Leave a Reply