Коротка відповідь
Схоже, дані в 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 отримує або зберігає наступну дату запуску. Можливо, вартих більшого розслідування в більш пізні терміни, коли у мене є вільний час ...