Introducción
Puede encontrar muchas guías sobre cómo hacer copias de seguridad y restaurar bases de datos. En este, mostraremos cómo se puede hacer esto utilizando los medios predeterminados de MS SQL Server.
Este ejemplo cubrirá una serie de enfoques, desde comprobar la integridad de la base de datos antes de realizar una copia de seguridad hasta restaurar la base de datos a partir de una copia de seguridad creada previamente.
La solución
En primer lugar, veamos el algoritmo general que usaremos para hacer una copia de seguridad de una base de datos:
1) Definir qué bases de datos necesitan copia de seguridad
2) Verificar la integridad de las bases de datos elegidas
3) Crear una copia de seguridad (completa, diferencial o copia del registro de transacciones) para cada una de las bases de datos elegidas
4) Comprobación de las copias de seguridad creadas
5) Compresión de los registros de transacciones (si es necesario)
A continuación, puede encontrar un ejemplo de implementación de este algoritmo.
Para definir qué bases de datos necesitan copia de seguridad, crearemos la siguiente tabla:
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [srv].[BackupSettings]( [DBID] [int] NOT NULL, [FullPathBackup] [nvarchar](255) NOT NULL, [DiffPathBackup] [nvarchar](255) NULL, [LogPathBackup] [nvarchar](255) NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_BackupSettings] PRIMARY KEY CLUSTERED ( [DBID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]; GO ALTER TABLE [srv].[BackupSettings] ADD CONSTRAINT [DF_BackupSettings_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate]; GO
El identificador de la base de datos se encuentra en la primera columna, 'FullPathBackup' contiene la ruta para la creación de una copia de seguridad completa (por ejemplo, 'disk:\…\'), y DiffPathBackup y LogPathBackup contienen rutas completas para la creación de copias diferenciales y del registro de transacciones. respectivamente. Si las columnas DiffPathBackup o LogPathBackup están vacías, no se creará la copia del registro diferencial y/o de transacciones para esta base de datos.
También podemos crear una representación basada en esta tabla:
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE view [srv].[vBackupSettings] as SELECT [DBID] ,DB_Name([DBID]) as [DBName] ,[FullPathBackup] ,[DiffPathBackup] ,[LogPathBackup] ,[InsertUTCDate] FROM [srv].[BackupSettings]; GO
Esta representación le permite comprobar de forma eficaz qué bases de datos participan en el proceso de copia de seguridad.
Ahora, creemos una representación que muestre la información del archivo de la base de datos de la representación del sistema sys.master_files:
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE view [inf].[ServerDBFileInfo] as SELECT @@Servername AS Server , File_id ,--DB file identifier. The base value for file_id is 1 Type_desc ,--Type file description Name as [FileName] ,--DB logical file name LEFT(Physical_Name, 1) AS Drive ,--Drive flag of the DB file location Physical_Name ,--Full file name in the OS RIGHT(physical_name, 3) AS Ext ,--File extension Size as CountPage, --Current file size in 8Kb pages round((cast(Size*8 as float))/1024,3) as SizeMb, --File size in Mb round((cast(Size*8 as float))/1024/1024,3) as SizeGb, --File size in Gb case when is_percent_growth=0 then Growth*8 else 0 end as Growth, --File growth in 8Kb pages case when is_percent_growth=0 then round((cast(Growth*8 as float))/1024,3) end as GrowthMb, --File growth in Mb case when is_percent_growth=0 then round((cast(Growth*8 as float))/1024/1024,3) end as GrowthGb, --File growth in Gb case when is_percent_growth=1 then Growth else 0 end as GrowthPercent, --File growth in percent is_percent_growth, --Percent growth attribute database_id, DB_Name(database_id) as [DB_Name], State,--File state state_desc as StateDesc,--File state description is_media_read_only as IsMediaReadOnly,--File is located on the drive as read-only (0 - and for writing) is_read_only as IsReadOnly,--file is flagged as read-only (0 - and for writing) is_sparse as IsSpace,--Sparse file is_name_reserved as IsNameReserved,--1 - Remote file name, accessible for use. --It is necessary to get a log backup before using the same name (name or physical_name arguments) again for a new file --0 - Filename, inaccessible for use create_lsn as CreateLsn,--Transaction registration number in the log (LSN) which was used to create the file drop_lsn as DropLsn,--LSN which was used to delete the file read_only_lsn as ReadOnlyLsn,--LSN which was used by the file group containing the file to change the "read and write" type to "read-only" (the latest change) read_write_lsn as ReadWriteLsn,--LSN which was used by the file group containing the file to change the "read-only" type to "read and write" (the latest change) differential_base_lsn as DifferentialBaseLsn,--A base for differential backup copies. Data extents which were changed after the LSN is included into the differential backup. differential_base_guid as DifferentialBaseGuid,--Unique identifier of the base backup copy which will be used to create a differential copy. differential_base_time as DifferentialBaseTime,--The time corresponding to differential_base_lsn redo_start_lsn as RedoStartLsn,--LSN used to determine the start of the next redo --Is NULL, except for the cases in which state = RESTORING or state = RECOVERY_PENDING redo_start_fork_guid as RedoStartForkGuid,--Unique identifier for the restoration fork point --first_fork_guid argument value of the next restored backup copy should be equal to this value redo_target_lsn as RedoTargetLsn,--LSN which serves as a stop point for an "online" mode redo in this file --Is NULL, except for the cases in which state = RESTORING or state = RECOVERY_PENDING redo_target_fork_guid as RedoTargetForkGuid,--Restoration fork on which the container can be restored. Used along with redo_target_lsn backup_lsn as BackupLsn--LSN of the most recent data or the file's differential backup copy FROM sys.master_files--database_files; GO
Para crear copias de seguridad completas, implementemos el siguiente procedimiento almacenado:
[expandir título =”Código “]
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [srv].[RunFullBackupDB] @ClearLog bit=1 --specifies whether the transaction log size should be reduced AS BEGIN /* Creating a full DB backup copy and checking the DB for integrity beforehand */ SET NOCOUNT ON; declare @dt datetime=getdate(); declare @year int=YEAR(@dt); declare @month int=MONTH(@dt); declare @day int=DAY(@dt); declare @hour int=DatePart(hour, @dt); declare @minute int=DatePart(minute, @dt); declare @second int=DatePart(second, @dt); declare @pathBackup nvarchar(255); declare @pathstr nvarchar(255); declare @DBName nvarchar(255); declare @backupName nvarchar(255); declare @sql nvarchar(max); declare @backupSetId as int; declare @FileNameLog nvarchar(255); declare @tbllog table( [DBName] [nvarchar](255) NOT NULL, [FileNameLog] [nvarchar](255) NOT NULL ); declare @tbl table ( [DBName] [nvarchar](255) NOT NULL, [FullPathBackup] [nvarchar](255) NOT NULL ); --Retrieving DB name and full paths for full backup copy creation insert into @tbl ( [DBName] ,[FullPathBackup] ) select DB_NAME([DBID]) ,[FullPathBackup] from [srv].[BackupSettings]; --Retrieving the DB name and names of the according transaction logs (as one DB can have multiple logs) insert into @tbllog([DBName], [FileNameLog]) select t.[DBName], tt.[FileName] as [FileNameLog] from @tbl as t inner join [inf].[ServerDBFileInfo] as tt on t.[DBName]=DB_NAME(tt.[database_id]) where tt.[Type_desc]='LOG'; --sequentially processing each of the DBs we got earlier while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; select top(1) @DBName=[DBName], @pathBackup=[FullPathBackup] from @tbl; set @[email protected]+N'_Full_backup_'+cast(@year as nvarchar(255))+N'_'+cast(@month as nvarchar(255))+N'_'+cast(@day as nvarchar(255))--+N'_' --+cast(@hour as nvarchar(255))+N'_'+cast(@minute as nvarchar(255))+N'_'+cast(@second as nvarchar(255)); set @[email protected]@sqldat.com+N'.bak'; --checking the DB for integrity set @sql=N'DBCC CHECKDB(N'+N''''[email protected]+N''''+N') WITH NO_INFOMSGS'; exec(@sql); --executing the backup copy creation procedure set @sql=N'BACKUP DATABASE ['[email protected]+N'] TO DISK = N'+N''''[email protected]+N''''+ N' WITH NOFORMAT, NOINIT, NAME = N'+N''''[email protected]+N''''+ N', CHECKSUM, STOP_ON_ERROR, SKIP, REWIND, COMPRESSION, STATS = 10;'; exec(@sql); --checking the backup copy we created select @backupSetId = position from msdb..backupset where [email protected] and backup_set_id=(select max(backup_set_id) from msdb..backupset where [email protected]); set @sql=N'Verification error. Backup copy information for "'[email protected]+'" database not found.'; if @backupSetId is null begin raiserror(@sql, 16, 1) end else begin set @sql=N'RESTORE VERIFYONLY FROM DISK = N'+''''[email protected]+N''''+N' WITH FILE = '+cast(@backupSetId as nvarchar(255)); exec(@sql); end --compressing the DB transaction logs if(@ClearLog=1) begin while(exists(select top(1) 1 from @tbllog where [DBName][email protected])) begin select top(1) @FileNameLog=FileNameLog from @tbllog where [email protected]; set @sql=N'USE ['[email protected]+N'];'+N' DBCC SHRINKFILE (N'+N''''[email protected]+N''''+N' , 0, TRUNCATEONLY)'; exec(@sql); delete from @tbllog where [email protected] and [email protected]; end end delete from @tbl where [DBName][email protected]; end END GO
[/expandir]
Según el código, podemos ver que este procedimiento proporciona una solución para los pasos restantes del algoritmo de creación de copias de seguridad.
Los procedimientos que crean copias diferenciales y de registros de transacciones se implementan de manera similar:
[expandir título =”Código “]
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [srv].[RunDiffBackupDB] @ClearLog bit=1 --specifies if the transaction log size should be reduced AS BEGIN /* Creating a differential DB backup copy */ SET NOCOUNT ON; declare @dt datetime=getdate(); declare @year int=YEAR(@dt); declare @month int=MONTH(@dt); declare @day int=DAY(@dt); declare @hour int=DatePart(hour, @dt); declare @minute int=DatePart(minute, @dt); declare @second int=DatePart(second, @dt); declare @pathBackup nvarchar(255); declare @pathstr nvarchar(255); declare @DBName nvarchar(255); declare @backupName nvarchar(255); declare @sql nvarchar(max); declare @backupSetId as int; declare @FileNameLog nvarchar(255); declare @tbl table ( [DBName] [nvarchar](255) NOT NULL, [DiffPathBackup] [nvarchar](255) NOT NULL ); declare @tbllog table( [DBName] [nvarchar](255) NOT NULL, [FileNameLog] [nvarchar](255) NOT NULL ); --Retrieving the DB name and full paths for creating differential backup copies insert into @tbl ( [DBName] ,[DiffPathBackup] ) select DB_NAME([DBID]) ,[DiffPathBackup] from [srv].[BackupSettings] where [DiffPathBackup] is not null; --Retrieving DB name and the full names of the according transaction log files (as one DB can have multiple logs) insert into @tbllog([DBName], [FileNameLog]) select t.[DBName], tt.[FileName] as [FileNameLog] from @tbl as t inner join [inf].[ServerDBFileInfo] as tt on t.[DBName]=DB_NAME(tt.[database_id]) where tt.[Type_desc]='LOG'; --sequentially processing each of the DBs we got earlier while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; select top(1) @DBName=[DBName], @pathBackup=[DiffPathBackup] from @tbl; set @[email protected]+N'_Diff_backup_'+cast(@year as nvarchar(255))+N'_'+cast(@month as nvarchar(255))+N'_'+cast(@day as nvarchar(255))+N'_' +cast(@hour as nvarchar(255))+N'_'+cast(@minute as nvarchar(255))+N'_'+cast(@second as nvarchar(255)); set @[email protected]@sqldat.com+N'.bak'; --checking the DB for integrity set @sql=N'DBCC CHECKDB(N'+N''''[email protected]+N''''+N') WITH NO_INFOMSGS'; exec(@sql); --executing the backup procedure set @sql=N'BACKUP DATABASE ['[email protected]+N'] TO DISK = N'+N''''[email protected]+N''''+ N' WITH DIFFERENTIAL, NOFORMAT, NOINIT, NAME = N'+N''''[email protected]+N''''+ N', CHECKSUM, STOP_ON_ERROR, SKIP, REWIND, COMPRESSION, STATS = 10;'; exec(@sql); --checking the backup copy we just created select @backupSetId = position from msdb..backupset where [email protected] and backup_set_id=(select max(backup_set_id) from msdb..backupset where [email protected]); set @sql=N'Verification error. Backup copy information for "'[email protected]+'" database not found.'; if @backupSetId is null begin raiserror(@sql, 16, 1) end else begin set @sql=N'RESTORE VERIFYONLY FROM DISK = N'+''''[email protected]+N''''+N' WITH FILE = '+cast(@backupSetId as nvarchar(255)); exec(@sql); end --compressing the DB transaction logs if(@ClearLog=1) begin while(exists(select top(1) 1 from @tbllog where [DBName][email protected])) begin select top(1) @FileNameLog=FileNameLog from @tbllog where [email protected]; set @sql=N'USE ['[email protected]+N'];'+N' DBCC SHRINKFILE (N'+N''''[email protected]+N''''+N' , 0, TRUNCATEONLY)'; exec(@sql); delete from @tbllog where [email protected] and [email protected]; end end delete from @tbl where [DBName][email protected]; end END GO
[/expandir]
Como comprobar la integridad de las bases de datos requiere muchos recursos, podemos omitirlo al crear una copia de seguridad diferencial.
[expandir título =”Código “]
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [srv].[RunLogBackupDB] @ClearLog bit=1 --specifies if the transaction log size should be reduced AS BEGIN /* Backing up the DB transaction log */ SET NOCOUNT ON; declare @dt datetime=getdate(); declare @year int=YEAR(@dt); declare @month int=MONTH(@dt); declare @day int=DAY(@dt); declare @hour int=DatePart(hour, @dt); declare @minute int=DatePart(minute, @dt); declare @second int=DatePart(second, @dt); declare @pathBackup nvarchar(255); declare @pathstr nvarchar(255); declare @DBName nvarchar(255); declare @backupName nvarchar(255); declare @sql nvarchar(max); declare @backupSetId as int; declare @FileNameLog nvarchar(255); declare @tbl table ( [DBName] [nvarchar](255) NOT NULL, [LogPathBackup] [nvarchar](255) NOT NULL ); declare @tbllog table( [DBName] [nvarchar](255) NOT NULL, [FileNameLog] [nvarchar](255) NOT NULL ); --Retrieving DB names and full paths for creating backup copies of transaction logs with a non-simple recovery model (full or bulk-logged). System DBs are also excluded insert into @tbl ( [DBName] ,[LogPathBackup] ) select DB_NAME(b.[DBID]) ,b.[LogPathBackup] from [srv].[BackupSettings] as b inner join sys.databases as d on b.[DBID]=d.[database_id] where d.recovery_model<3 and DB_NAME([DBID]) not in ( N'master', N'tempdb', N'model', N'msdb', N'ReportServer', N'ReportServerTempDB' ) and [LogPathBackup] is not null; --Retrieving DB name and the full names of the according transaction log files (as one DB can have multiple logs) insert into @tbllog([DBName], [FileNameLog]) select t.[DBName], tt.[FileName] as [FileNameLog] from @tbl as t inner join [inf].[ServerDBFileInfo] as tt on t.[DBName]=DB_NAME(tt.[database_id]) where tt.[Type_desc]='LOG'; --sequentially processing each of the DBs we got earlier while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; select top(1) @DBName=[DBName], @pathBackup=[LogPathBackup] from @tbl; set @[email protected]+N'_Log_backup_'+cast(@year as nvarchar(255))+N'_'+cast(@month as nvarchar(255))+N'_'+cast(@day as nvarchar(255))+N'_' +cast(@hour as nvarchar(255))+N'_'+cast(@minute as nvarchar(255))+N'_'+cast(@second as nvarchar(255)); set @[email protected]@sqldat.com+N'.trn'; --executing the backup procedure set @sql=N'BACKUP LOG ['[email protected]+N'] TO DISK = N'+N''''[email protected]+N''''+ N' WITH NOFORMAT, NOINIT, NAME = N'+N''''[email protected]+N''''+ N', CHECKSUM, STOP_ON_ERROR, SKIP, REWIND, COMPRESSION, STATS = 10;'; exec(@sql); --Checking the transaction log backup copy we just created select @backupSetId = position from msdb..backupset where [email protected] and backup_set_id=(select max(backup_set_id) from msdb..backupset where [email protected]); set @sql=N'Verification error. Backup copy information for "'[email protected]+'" database not found.'; if @backupSetId is null begin raiserror(@sql, 16, 1) end else begin set @sql=N'RESTORE VERIFYONLY FROM DISK = N'+''''[email protected]+N''''+N' WITH FILE = '+cast(@backupSetId as nvarchar(255)); exec(@sql); end --compressing the DB transaction logs if(@ClearLog=1) begin while(exists(select top(1) 1 from @tbllog where [DBName][email protected])) begin select top(1) @FileNameLog=FileNameLog from @tbllog where [email protected]; set @sql=N'USE ['[email protected]+N'];'+N' DBCC SHRINKFILE (N'+N''''[email protected]+N''''+N' , 0, TRUNCATEONLY)'; exec(@sql); delete from @tbllog where [email protected] and [email protected]; end end delete from @tbl where [DBName][email protected]; end END GO
[/expandir]
Como se dijo anteriormente, verificar la integridad de las bases de datos es una tarea que requiere muchos recursos. Combinado con el hecho de que las copias de respaldo del registro de transacciones generalmente deben crearse con bastante frecuencia, esto nos da una razón para omitir la verificación de integridad al crear una copia del registro de transacciones.
También tenga en cuenta que las copias de seguridad completas de las bases de datos "maestra", "msdb" y "modelo" deben realizarse periódicamente.
Para automatizar el proceso de creación de copias de seguridad, solo deberá realizar una llamada de los procedimientos implementados anteriormente en el Programador de tareas de Windows, trabajos de agentes o cualquier servicio similar disponible.
Deberá configurar la frecuencia de llamada para cada uno de esos procedimientos individualmente en función de los picos de carga, las mesetas de actividad, etc.
El enfoque básico es el siguiente:
1) Crear una copia de seguridad completa una vez al día
2) Crear copias de seguridad diferenciales cada 2 a 4 horas
3) Crear copias de seguridad del registro de transacciones cada 5 a 60 minutos
Tenga en cuenta que, por lo general, las bases de datos participan en el sistema de acceso rápido y a prueba de fallas. Y, si este último utiliza copias de seguridad del registro de transacciones, es de vital importancia no interferir con el procedimiento. Más específicamente, esto significa que varios procesos diferentes no deben crear copias del registro de transacciones; si esto sucede, se perderá la secuencia de copia de seguridad de estas copias.
Aquí, hemos visto ejemplos de cada base de datos procesada secuencialmente, una a la vez. Sin embargo, podemos lograr un procesamiento paralelo en el entorno de producción, lo que permite realizar varias copias de seguridad simultáneamente. Esto se puede abordar de diferentes maneras. Por ejemplo, llamando al siguiente procedimiento almacenado:
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [inf].[RunAsyncExecute] ( @sql nvarchar(max), @jobname nvarchar(57) = null, @database nvarchar(128)= null, @owner nvarchar(128) = null ) AS BEGIN /* Asynchronous package execution via the Agent's jobs RunAsyncExecute - asynchronous execution of T-SQL command or stored prodecure 2012 Antonin Foller, Motobit Software, www.motobit.com http://www.motobit.com/tips/detpg_async-execute-sql/ */ SET NOCOUNT ON; declare @id uniqueidentifier; --Create unique job name if the name is not specified if (@jobname is null) set @jobname= ''; set @jobname = @jobname + '_async_' + convert(varchar(64),NEWID()); if (@owner is null) set @owner = 'sa'; --Create a new job, get job ID execute msdb..sp_add_job @jobname, @[email protected], @[email protected] OUTPUT; --Specify a job server for the job execute msdb..sp_add_jobserver @[email protected]; --Specify a first step of the job - the SQL command --(@on_success_action = 3 ... Go to next step) execute msdb..sp_add_jobstep @[email protected], @step_name='Step1', @command = @sql, @database_name = @database, @on_success_action = 3; --Specify next step of the job - delete the job declare @deletecommand varchar(200); set @deletecommand = 'execute msdb..sp_delete_job @job_name='''[email protected]+''''; execute msdb..sp_add_jobstep @[email protected], @step_name='Step2', @command = @deletecommand; --Start the job execute msdb..sp_start_job @[email protected]; END GO
Aquí, la asincronía se logra creando dinámicamente los trabajos del Agente, ejecutándolos y eliminándolos después.
Ahora, veamos el algoritmo general para restaurar bases de datos a partir de copias de seguridad creadas previamente en un entorno diferente/de prueba:
1) Definir qué bases de datos se deben restaurar y la ubicación de sus copias de seguridad
2) Restaurar las bases de datos
3) Verificar la integridad de las bases de datos restauradas
Ahora, veremos una implementación de un algoritmo que restaura una base de datos a partir de una copia de seguridad completa. Para una copia diferencial, el procedimiento es similar:la única diferencia es que primero se debe restaurar una copia de respaldo completa, seguida de la copia diferencial.
Para definir qué bases de datos deben restaurarse, así como la ubicación de sus copias de seguridad, creemos dos tablas como se muestra a continuación:
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [srv].[RestoreSettings]( [DBName] [nvarchar](255) NOT NULL, [FullPathRestore] [nvarchar](255) NOT NULL, [DiffPathRestore] [nvarchar](255) NOT NULL, [LogPathRestore] [nvarchar](255) NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_RestoreSettings] PRIMARY KEY CLUSTERED ( [DBName] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]; GO ALTER TABLE [srv].[RestoreSettings] ADD CONSTRAINT [DF_RestoreSettings_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate]; GO
Aquí, el propósito de las columnas es análogo al de la tabla [srv].[BackupSettings]. La única diferencia es que la ruta completa se usará para ubicar las copias de respaldo para la restauración y no para crear nuevas.
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [srv].[RestoreSettingsDetail]( [Row_GUID] [uniqueidentifier] NOT NULL, [DBName] [nvarchar](255) NOT NULL, [SourcePathRestore] [nvarchar](255) NOT NULL, TargetPathRestore [nvarchar](255) NOT NULL, [Ext] [nvarchar](255) NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_RestoreSettingsDetail] PRIMARY KEY CLUSTERED ( [Row_GUID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]; GO ALTER TABLE [srv].[RestoreSettingsDetail] ADD CONSTRAINT [DF_RestoreSettingsDetail_Row_GUID] DEFAULT (newid()) FOR [Row_GUID]; GO ALTER TABLE [srv].[RestoreSettingsDetail] ADD CONSTRAINT [DF_RestoreSettingsDetail_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate]; GO
Esta tabla es necesaria para definir los nombres de archivo completos de la base de datos que se está restaurando, que luego se usan para transferencias adicionales (por ejemplo, [SourcePathRestore]='Nombre de archivo lógico' y [TargetPathRestore]='disco:\…\Nombre de archivo físico ', while [Ext]='Extensión de archivo')
En realidad, podemos definir nombres lógicos de los archivos de la base de datos usando la siguiente consulta:
RESTORE FILELISTONLY FROM DISK ='disk:\...\backup copy.BAK';
Obtener información sobre las copias de seguridad ubicadas en un archivo se puede hacer de esta manera:
RESTORE HEADERONLY FROM DISK='disk:\...\backup copy.BAK';
A continuación, tenemos una implementación de un procedimiento almacenado utilizado para restaurar una base de datos a partir de una copia de seguridad completa y verificar la integridad de los datos:
[expandir título =”Código “]
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [srv].[RunFullRestoreDB] AS BEGIN /* Recovering a DB from a full backup copy and checking the DB for integrity */ SET NOCOUNT ON; declare @dt datetime=DateAdd(day,-2,getdate()); declare @year int=YEAR(@dt); declare @month int=MONTH(@dt); declare @day int=DAY(@dt); declare @hour int=DatePart(hour, @dt); declare @minute int=DatePart(minute, @dt); declare @second int=DatePart(second, @dt); declare @pathBackup nvarchar(255); declare @pathstr nvarchar(255); declare @DBName nvarchar(255); declare @backupName nvarchar(255); declare @sql nvarchar(max); declare @backupSetId as int; declare @FileNameLog nvarchar(255); declare @SourcePathRestore nvarchar(255); declare @TargetPathRestore nvarchar(255); declare @Ext nvarchar(255); declare @tbl table ( [DBName] [nvarchar](255) NOT NULL, [FullPathRestore] [nvarchar](255) NOT NULL ); declare @tbl_files table ( [DBName] [nvarchar](255) NOT NULL, [SourcePathRestore] [nvarchar](255) NOT NULL, [TargetPathRestore] [nvarchar](255) NOT NULL, [Ext] [nvarchar](255) NOT NULL ); --retrieving a list of DB names and the paths to full backup copies insert into @tbl ( [DBName] ,[FullPathRestore] ) select [DBName] ,[FullPathRestore] from [srv].[RestoreSettings]; --retrieving detailed info about the new DB files location insert into @tbl_files ( [DBName] ,[SourcePathRestore] ,[TargetPathRestore] ,[Ext] ) select [DBName] ,[SourcePathRestore] ,[TargetPathRestore] ,[Ext] from [srv].[RestoreSettingsDetail]; --processing each of the DBs we got earlier while(exists(select top(1) 1 from @tbl)) begin set @backupSetId=NULL; select top(1) @DBName=[DBName], @pathBackup=[FullPathRestore] from @tbl; set @[email protected]+N'_Full_backup_'+cast(@year as nvarchar(255))+N'_'+cast(@month as nvarchar(255))+N'_'+cast(@day as nvarchar(255))--+N'_' --+cast(@hour as nvarchar(255))+N'_'+cast(@minute as nvarchar(255))+N'_'+cast(@second as nvarchar(255)); set @[email protected]@sqldat.com+N'.bak'; --creating a backup query and executing it set @sql=N'RESTORE DATABASE ['[email protected]+N'_Restore] FROM DISK = N'+N''''[email protected]+N''''+ N' WITH FILE = 1,'; while(exists(select top(1) 1 from @tbl_files where [DBName][email protected])) begin select top(1) @SourcePathRestore=[SourcePathRestore], @TargetPathRestore=[TargetPathRestore], @Ext=[Ext] from @tbl_files where [DBName][email protected]; set @[email protected]+N' MOVE N'+N''''[email protected]+N''''+N' TO N'+N''''[email protected]+N'_Restore.'[email protected]+N''''+N','; delete from @tbl_files where [DBName][email protected] and [SourcePathRestore][email protected] and [Ext][email protected]; end set @[email protected]+N' NOUNLOAD, REPLACE, STATS = 5'; exec(@sql); --checking the DB for integrity set @sql=N'DBCC CHECKDB(N'+N''''[email protected]+'_Restore'+N''''+N') WITH NO_INFOMSGS'; exec(@sql); delete from @tbl where [DBName][email protected]; end END
[/expandir]
Para especificar qué copia de seguridad completa se debe usar para la restauración, se usa un nombre de archivo especialmente estructurado:
Para automatizar este proceso de restauración de la base de datos, la llamada del procedimiento almacenado que implementamos debe colocarse en el Programador de tareas de Windows, los trabajos del Agente o cualquier servicio disponible similar.
Puede ver las copias de seguridad de la base de datos más recientes utilizando la siguiente representación:
USE [DB_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE VIEW [inf].[vServerLastBackupDB] as with backup_cte as ( select bs.[database_name], backup_type = case bs.[type] when 'D' then 'database' when 'L' then 'log' when 'I' then 'differential' else 'other' end, bs.[first_lsn], bs.[last_lsn], bs.[backup_start_date], bs.[backup_finish_date], cast(bs.[backup_size] as decimal(18,3))/1024/1024 as BackupSizeMb, rownum = row_number() over ( partition by bs.[database_name], type order by bs.[backup_finish_date] desc ), LogicalDeviceName = bmf.[logical_device_name], PhysicalDeviceName = bmf.[physical_device_name], bs.[server_name], bs.[user_name] FROM msdb.dbo.backupset bs INNER JOIN msdb.dbo.backupmediafamily bmf ON [bs].[media_set_id] = [bmf].[media_set_id] ) select [server_name] as [ServerName], [database_name] as [DBName], [user_name] as [USerName], [backup_type] as [BackupType], [backup_start_date] as [BackupStartDate], [backup_finish_date] as [BackupFinishDate], [BackupSizeMb], --uncompressed size [LogicalDeviceName], [PhysicalDeviceName], [first_lsn] as [FirstLSN], [last_lsn] as [LastLSN] from backup_cte where rownum = 1;
El resultado
En esta guía, hemos analizado la implementación de un proceso de copia de seguridad automatizado en un servidor y la consiguiente restauración en otro diferente (un servidor de prueba, por ejemplo).
Este método nos permite automatizar el proceso de creación de copias de seguridad, verificar las copias de seguridad al restaurarlas y ajustar los procesos que se muestran arriba.
Fuentes:
Copia de seguridad
Restaurar
Copia de seguridad
CHECKDB
SHRINKFILE
sys.master_files