Назад | Перейти на главную страницу

Восстановление определенного задания из резервной копии MSDB?

Нас попросили восстановить конкретное задание SQL 2005 из того, как оно существовало в определенное время в прошлом. У нас есть резервные копии базы данных MSDB за этот период времени, но я не могу перезаписать текущую базу данных MSDB, потому что я не хочу потерять последние изменения в других заданиях на этом сервере.

Если я восстановлю его как копию (назовите его MSDB_old или что-то в этом роде), как я могу извлечь информацию для этого единственного задания? Или мне нужно будет восстановить его через базу данных MSDB на рабочем сервере?

Нет необходимости восстанавливать на чистый сервер, вы можете восстановить его примерно так, как вы говорите (MSDB_old), и выполнить запрос, чтобы вернуть свою работу:

USE msdb_old
SELECT * FROM sysjobs
JOIN sysjobsteps ON sysjobs.job_id=sysjobsteps.job_id
WHERE sysjobs.NAME='My Lost Job'
ORDER BY sysjobsteps.step_id

Вам придется восстановить

  • запись в sysjobs
  • каждая запись в sysjobsteps, связанная с указанной выше записью в sysjobs
  • записи в sysjobhistory, если вы хотите вернуть историю
  • записи в sysjobschedules, чтобы вернуть свои расписания

РЕДАКТИРОВАТЬ: Вот сценарий, который должен делать это в SQL 2005 и 2008 (при условии, что ваша работа называлась «Моя потерянная работа» и вы восстановили ее в MSDB_Old)

DECLARE @JobID UNIQUEIDENTIFIER
SELECT @JobID = job_id FROM msdb_old.dbo.sysjobs WHERE NAME='My Lost Job'

INSERT msdb.dbo.sysjobs
SELECT * FROM msdb_old.dbo.sysjobs
WHERE job_id=@JobID

INSERT msdb.dbo.sysjobsteps
SELECT * FROM msdb_old.dbo.sysjobsteps
WHERE job_id=@JobID

SET IDENTITY_INSERT msdb.dbo.sysjobhistory ON
INSERT msdb.dbo.sysjobhistory
    (instance_id,job_id,step_id,step_name,sql_message_id,sql_severity,
     [message],run_status,run_date,run_time,run_duration,operator_id_emailed,
     operator_id_netsent,operator_id_paged,retries_attempted,[server])
SELECT
    instance_id,job_id,step_id,step_name,sql_message_id,sql_severity,
    [message],run_status,run_date,run_time,run_duration,operator_id_emailed,
    operator_id_netsent,operator_id_paged,retries_attempted,[server]
FROM msdb_old.dbo.sysjobhistory
WHERE job_id=@JobID
SET IDENTITY_INSERT msdb.dbo.sysjobhistory OFF

INSERT msdb.dbo.sysjobschedules
SELECT * FROM msdb_old.dbo.sysjobschedules
WHERE job_id=@JobID

Сценарий в общих чертах основан на вот этот в принятом ответе. Он был обновлен для SQL 2014 с обработкой исключений, атомарными транзакциями и некоторыми другими улучшениями.

-- Script for SQL 2014
DECLARE @JobID UNIQUEIDENTIFIER
declare @servername sysname

set @servername = @@SERVERNAME

SELECT @JobID = job_id 
FROM msdb_old.dbo.sysjobs 
WHERE name='My Lost Job'

BEGIN TRAN

BEGIN TRY

INSERT msdb.dbo.sysjobs
SELECT * FROM msdb_old.dbo.sysjobs
WHERE job_id=@JobID

INSERT msdb.dbo.sysjobsteps
SELECT * FROM msdb_old.dbo.sysjobsteps
WHERE job_id=@JobID

SET IDENTITY_INSERT msdb.dbo.sysjobhistory ON
INSERT msdb.dbo.sysjobhistory
 (instance_id,job_id,step_id,step_name,sql_message_id,sql_severity,
 [message],run_status,run_date,run_time,run_duration,operator_id_emailed,
 operator_id_netsent,operator_id_paged,retries_attempted,[server])
SELECT
 instance_id,job_id,step_id,step_name,sql_message_id,sql_severity,
 [message],run_status,run_date,run_time,run_duration,operator_id_emailed,
 operator_id_netsent,operator_id_paged,retries_attempted,[server]
FROM msdb_old.dbo.sysjobhistory
WHERE job_id=@JobID
SET IDENTITY_INSERT msdb.dbo.sysjobhistory OFF

-- New insert in sysschedules 
SET IDENTITY_INSERT msdb.dbo.sysschedules ON
INSERT msdb.dbo.sysschedules (schedule_id, schedule_uid,
         originating_server_id, name, owner_sid, enabled,
         freq_type,freq_interval, freq_subday_type,
         freq_subday_interval, freq_relative_interval,
         freq_recurrence_factor, active_start_date, 
         active_end_date, active_start_time, active_end_time,
         date_created, date_modified, version_number)
SELECT schedule_id, schedule_uid, originating_server_id, name,
       owner_sid, enabled, freq_type, freq_interval, freq_subday_type,
       freq_subday_interval, freq_relative_interval,
       freq_recurrence_factor, active_start_date, active_end_date,
       active_start_time, active_end_time, date_created, date_modified,
       version_number 
FROM msdb_old.dbo.sysschedules a
WHERE schedule_id = (select schedule_id from msdb_old.dbo.sysjobschedules b where job_id=@JobID )
SET IDENTITY_INSERT msdb.dbo.sysschedules OFF

INSERT msdb.dbo.sysjobschedules
SELECT * FROM msdb_old.dbo.sysjobschedules
WHERE job_id=@JobID

-- Alter job as local job
EXEC msdb.dbo.sp_add_jobserver @job_id=@JobID, @server_name = @servername

END TRY
BEGIN CATCH
SELECT
    ERROR_NUMBER() AS ErrorNumber,
    ERROR_SEVERITY() AS ErrorSeverity,
    ERROR_STATE() AS ErrorState,
    ERROR_PROCEDURE() AS ErrorProcedure,
    ERROR_LINE() AS ErrorLine,
    ERROR_MESSAGE() AS ErrorMessage;

    ROLLBACK TRAN

    RETURN
END CATCH

COMMIT TRAN

Самый простой способ извлечь отдельное задание из MSDB - щелкнуть его правой кнопкой мыши в SSMS и сказать «Задание сценария», а затем передать сценарий на целевой сервер и запустить его, чтобы воссоздать задание (возможно, с некоторыми изменениями).

Это работает только в том случае, если msdb восстанавливается как msdb - это означает, что в вашем случае вам придется восстанавливать резервную копию как msdb на рабочем сервере.

Я предполагаю, что вы можете восстановить его как копию msdb, а затем вручную извлечь все из различных таблиц msdb_copy.dbo.sysjobs / sysjobsteps / sysjobschedules / sysjobservers с помощью соединения.

Надеюсь это поможет!

Привет, хочу дополнить ответ Сквиллмана. Тестировал в 2008 R2.

Во-первых, исправив ошибку с нарушением FK с sysjobschedules и sysschedules.

Во-вторых, запустив dbo.sp_add_jobserver.

Наконец, заставив его пройти через все задания в msdb_old.dbo.sysjobs для полной репликации.

DECLARE @JobID UNIQUEIDENTIFIER
declare @jobname nvarchar(128)

DECLARE MY_CURSOR CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR 
SELECT DISTINCT job_id 
FROM msdb_old.dbo.sysjobs

OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @JobID
WHILE @@FETCH_STATUS = 0

BEGIN
SELECT @jobname = name FROM msdb_old.dbo.sysjobs WHERE job_id=@jobid
print @jobname

print 'insert in sysjobs'
INSERT msdb.dbo.sysjobs
SELECT * FROM msdb_old.dbo.sysjobs
WHERE job_id=@JobID

print 'insert in sysjobsteps'
INSERT msdb.dbo.sysjobsteps
SELECT * FROM msdb_old.dbo.sysjobsteps
WHERE job_id=@JobID

print 'insert in sysjobhistory'
SET IDENTITY_INSERT msdb.dbo.sysjobhistory ON
INSERT msdb.dbo.sysjobhistory
    (instance_id,job_id,step_id,step_name,sql_message_id,sql_severity,
     [message],run_status,run_date,run_time,run_duration,operator_id_emailed,
     operator_id_netsent,operator_id_paged,retries_attempted,[server])
SELECT
    instance_id,job_id,step_id,step_name,sql_message_id,sql_severity,
    [message],run_status,run_date,run_time,run_duration,operator_id_emailed,
    operator_id_netsent,operator_id_paged,retries_attempted,[server]
FROM msdb_old.dbo.sysjobhistory
WHERE job_id=@JobID
SET IDENTITY_INSERT msdb.dbo.sysjobhistory OFF

print 'insert in sysschedules'
SET IDENTITY_INSERT msdb.dbo.sysschedules ON
INSERT msdb.dbo.sysschedules
( [schedule_id]
,[schedule_uid]
,[originating_server_id]
,[name]
,[owner_sid]
,[enabled]
,[freq_type]
,[freq_interval]
,[freq_subday_type]
,[freq_subday_interval]
,[freq_relative_interval]
,[freq_recurrence_factor]
,[active_start_date]
,[active_end_date]
,[active_start_time]
,[active_end_time]
,[date_created]
,[date_modified]
,[version_number])
SELECT  s.[schedule_id]
,s.[schedule_uid]
,s.[originating_server_id]
,s.[name]
,s.[owner_sid]
,s.[enabled]
,s.[freq_type]
,s.[freq_interval]
,s.[freq_subday_type]
,s.[freq_subday_interval]
,s.[freq_relative_interval]
,s.[freq_recurrence_factor]
,s.[active_start_date]
,s.[active_end_date]
,s.[active_start_time]
,s.[active_end_time]
,s.[date_created]
,s.[date_modified]
,s.[version_number]
FROM msdb_old.dbo.sysschedules s, msdb_old.dbo.sysjobschedules j
WHERE j.job_id=@JobID and s.schedule_id = j.schedule_id
SET IDENTITY_INSERT msdb.dbo.sysschedules OFF

print 'insert in sysjobschedules'
INSERT msdb.dbo.sysjobschedules
SELECT * FROM msdb_old.dbo.sysjobschedules
WHERE job_id=@JobID

print'exec adds job in server'
use msdb
EXEC dbo.sp_add_jobserver @job_id = @jobid

FETCH NEXT FROM MY_CURSOR INTO @JobID
END

CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR

просто восстановите на любой сервер с новым именем, я делал это много раз раньше ...