Як і коли агент SQL оновлює значення next_run_date / next_run_time?


13

Я працював над кодом у T-SQL, щоб додати нові розклади до завдання SQL Agent, використовуючи процедуру sp_add_jobschedule proc в базі даних msdb. Коли я додаю новий графік (як правило, повторний раз на певну дату / час) і одразу переглядаю значення в систематизованих таблицях і сиспланах, я можу побачити, що новий графік був доданий і прив’язаний до завдання_id для мого агента SQL робота. Однак значення next_run_date та next_run_time мають у них 0. Коли я повертаюся і знову дивлюся на них через 2 або 3 хвилини, вони все ще показують 0 у них. Однак, коли я повернувся ще 5 або 10 хвилин пізніше, він тепер правильно відображає значення дати та часу, що відповідають наступному запланованому виконанню.

Отже, мої запитання:

  • Як часто ці значення оновлюються?
  • Який процес оновлює ці значення?
  • Якщо я мав би додати графік, який був, скажімо, на 1 хвилину в майбутньому, чи це означає, що робота не запуститься, оскільки next_run_date / час ще не було оновлено?

Приклад коду, який я використовую, щоб додати новий графік:

exec msdb.dbo.sp_add_jobschedule @job_id = @jobID
                    , @name = @JobName
                    , @enabled = 1
                    , @freq_type = 1
                    , @freq_interval = 0
                    , @freq_subday_type = 0
                    , @freq_subday_interval = 0
                    , @freq_relative_interval = 0
                    , @freq_recurrence_factor = 0
                    , @active_start_date = @ScheduleRunDate
                    , @active_end_date = 99991231
                    , @active_start_time = @ScheduleRunTime
                    , @active_end_time = 235959

де @jobID є двійковим (16), у якому розміщено task_id відповідної роботи, @ScheduleRunDate та @ScheduleRunTime - це INT з датою та часом відповідно.


3
Він оновлюється через завдання SQL Agent. Який оновлюється через завдання SQL Agent. Рекурсіони об’єднуються!
Аарон Бертран

1
Вибачення. Якось не мав шансу обернутися назад.
BBlake

Відповіді:


16

Коротка відповідь

Схоже, дані в msdb.dbo.sysjobschedulesоновлюються фоновою ниткою в SQL Agent, ідентифікованої як SQLAgent - Schedule Saverкожні 20 хвилин (або рідше, якщо xp_sqlagent_notifyне було викликано і тим часом жодні завдання не виконувались тим часом).

Для більш точної інформації дивіться next_scheduled_run_dateв msdb.dbo.sysjobactivity. Він оновлюється в режимі реального часу будь-коли, коли змінено роботу або виконано роботу. Як додатковий бонус, вони sysjobactivityзберігають дані правильним способом (як стовпець дати), що робить його набагато простіше працювати з тими дурними INT.

Ось така коротка відповідь:

Це може пройти до 20 хвилин, перш ніж систематичні графіки відображають істину; однак систематичність завжди буде актуальною. Якщо ви хочете набагато детальніше про це, або як я це зрозумів ...


Довга відповідь

Якщо ви хочете на мить слідкувати за кроликом, коли ви телефонуєте sp_add_jobschedule, цей ланцюжок подій приводиться в рух:

msdb.dbo.sp_add_jobschedule == calls ==> msdb.dbo.sp_add_schedule
                                         msdb.dbo.sp_attach_schedule

msdb.dbo.sp_attach_schedule == calls ==> msdb.dbo.sp_sqlagent_notify

msdb.dbo.sp_sqlagent_notify == calls ==> msdb.dbo.xp_sqlagent_notify

Тепер ми не можемо більше переслідувати кролика, тому що ми не можемо зазирнути в те, що xp_sqlagent_notifyробить. Але я думаю, що ми можемо припустити, що ця розширена процедура взаємодіє зі службою агента і повідомляє, що в цій конкретній роботі та графіку відбулися зміни. Запустивши трасування на стороні сервера, ми можемо побачити, що негайно SQL Agent викликає такий динамічний SQL:

exec sp_executesql N'DECLARE @nextScheduledRunDate DATETIME 
  SET @nextScheduledRunDate = msdb.dbo.agent_datetime(@P1, @P2) 
  UPDATE msdb.dbo.sysjobactivity 
    SET next_scheduled_run_date = @nextScheduledRunDate 
    WHERE session_id = @P3 AND job_id = @P4',
N'@P1 int,@P2 int,@P3 int,@P4 uniqueidentifier',
20120819,181600,5,'36924B24-9706-4FD7-8B3A-1F9F0BECB52C'

Здається, sysjobactivityоновляється одразу, і sysjobschedulesоновлюється лише за розкладом. Якщо ми змінимо новий графік, щоб бути раз на день, наприклад

@freq_type=4, 
@freq_interval=1, 
@freq_subday_type=1, 
@freq_subday_interval=0, 
@freq_relative_interval=0, 
@freq_recurrence_factor=1, 

Ми все ще бачимо негайне оновлення, sysjobactivityяк зазначено вище, а потім ще одне оновлення після завершення завдання. Різні оновлення надходять із фонових та інших потоків у SQL Agent, наприклад:

SQLAgent - Job Manager
SQLAgent - Update job activity
SQLAgent - Job invocation engine
SQLAgent - Schedule Saver

Фоновий потік (нитка "Захист розкладу") врешті-решт з’являється та оновлюється sysjobschedules; з мого первинного розслідування виявляється, що це кожні 20 хвилин, і це відбувається лише в тому випадку, якщо xp_sqlagent_notifyмені було викликано через зміни, внесені до роботи з моменту останнього запуску (я не проводив ніяких додаткових тестувань, щоб побачити, що станеться, якщо одна робота була змінився і інший запустився, якщо потік "Захист розкладу" оновлює і те, і інше - я підозрюю, що він повинен, але це залишить читачеві як вправу).

Я не впевнений, чи зміщений 20-хвилинний цикл з моменту запуску агента SQL, або з півночі, або з чогось конкретного машинного. На двох різних примірниках на одному фізичному сервері потік " sysjobschedulesЗахист розкладу" оновлювався в обох випадках майже в один і той же час - 18:31:37 і 18:51:37 на одному, і 18:31:39 & 18:51:39 з іншого. Я не запускав агент SQL Server одночасно на цих серверах, але є віддалена можливість, коли час запуску сталося зсувом 20 хвилин. Сумніваюсь у цьому, але зараз я не встигаю підтвердити, перезапустивши Агента на одному з них і чекаючи, коли відбудуться нові оновлення.

Я знаю, хто це зробив, і коли це сталося, тому що я поставив курок і захопив його, якщо я не зміг його знайти у сліді, або ненавмисно відфільтрував його.

CREATE TABLE dbo.JobAudit
(
  [action] CHAR(1),
  [table] CHAR(1), 
  hostname SYSNAME NOT NULL DEFAULT HOST_NAME(), 
  appname SYSNAME  NOT NULL DEFAULT PROGRAM_NAME(),
  dt DATETIME2     NOT NULL DEFAULT SYSDATETIME()
);

CREATE TRIGGER dbo.schedule1 ON dbo.sysjobactivity FOR INSERT
AS
  INSERT dbo.JobAudit([action], [table] SELECT 'I', 'A';
GO
CREATE TRIGGER dbo.schedule2 ON dbo.sysjobactivity FOR UPDATE
AS
  INSERT dbo.JobAudit([action], [table] SELECT 'U', 'A';
GO
CREATE TRIGGER dbo.schedule3 ON dbo.sysjobschedules FOR INSERT
AS
  INSERT dbo.JobAudit([action], [table] SELECT 'I', 'S';
GO
CREATE TRIGGER dbo.schedule4 ON dbo.sysjobschedules FOR UPDATE
AS
  INSERT dbo.JobAudit([action], [table] SELECT 'U', 'S';
GO

Однак це не важко спіймати зі стандартним слідом, цей навіть проходить як нединамічний DML:

UPDATE msdb.dbo.sysjobschedules 
  SET next_run_date = 20120817, 
      next_run_time = 20000 
 WHERE (job_id = 0xB87B329BFBF7BA40B30D9B27E0B120DE 
 and schedule_id = 8)

Якщо ви хочете запустити більш відфільтрований слід, щоб відстежувати цю поведінку з часом (наприклад, зберігається через перезапуск SQL Agent замість запиту на замовлення), ви можете запустити той, який має appname = 'SQLAgent - Schedule Saver'...

Тому я думаю, що якщо ви хочете дізнатися наступний час запуску, подивіться sysjobactivity, ні sysjobschedules. Ця таблиця безпосередньо оновлюється Агентом або його потоковими потоками ("Оновити завдання роботи", "Менеджер завдань" та "Двигун викликів робіт"), коли відбувається діяльність або як повідомляється xp_sqlagent_notify.

Однак майте на увазі, що дуже легко вилучити будь-яку таблицю - оскільки немає захисту від видалення даних з цих таблиць. (Отже, якщо ви вирішили очистити, наприклад, ви можете легко видалити всі рядки для цієї роботи з таблиці активності.) У цьому випадку я точно не впевнений, як агент SQL Server отримує або зберігає наступну дату запуску. Можливо, вартих більшого розслідування в більш пізні терміни, коли у мене є вільний час ...


Якщо завдання ще не запущено вперше, sysjobschedules (зрештою) покаже правильні значення для next_run_date і next_run_time, тоді як sysjobactivity.next_scheduled_run_date залишається недійсним до першого виконання. Отримуючи значення від sysjobactivity, вам потрібно зробити це в підзапиті, який групується по task_id і отримує MAX (next_scheduled_run_date).
Марк Фріман

0

msdb.dbo.sp_help_jobзавжди з'являється, щоб повернути правильний фактичний next_run_date/ next_run_time.

Він використовує sp_get_composite_job_info, що робить наступний виклик, щоб фактично отримати next_run_date/time.

      IF ((@@microsoftversion / 0x01000000) >= 8) -- SQL Server 8.0 or greater
        INSERT INTO @xp_results
        EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner, @job_id
      ELSE
        INSERT INTO @xp_results
        EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner

Оскільки, sysjobscheduleздається, ненадійний, я б просто скористався sp_help_job.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.