Làm thế nào và khi nào SQL Agent cập nhật các giá trị next_run_date / next_run_time?


13

Tôi đã làm việc với mã trong T-SQL để thêm lịch biểu mới vào công việc Tác nhân SQL bằng cách sử dụng sp_add_jobschedule Proc trong cơ sở dữ liệu msdb. Khi tôi thêm lịch biểu mới (thường là chạy một lần vào một ngày / thời gian cụ thể) và ngay lập tức xem xét các giá trị trong sysjobschedules và sysschedules, tôi có thể thấy rằng lịch biểu mới đã được thêm vào và được gắn với job_id cho Tác nhân SQL của tôi việc làm. Tuy nhiên, các giá trị cho next_run_date và next_run_time có 0 trong đó. Khi tôi quay lại và nhìn lại họ sau 2 hoặc 3 phút, họ vẫn hiển thị 0 trong đó. Tuy nhiên, khi tôi quay lại thêm 5 hoặc 10 phút sau, bây giờ nó hiển thị chính xác các giá trị ngày và thời gian tương ứng với lần chạy theo lịch trình tiếp theo.

Vì vậy, câu hỏi của tôi là:

  • Làm thế nào thường làm những giá trị này được cập nhật?
  • Quá trình nào cập nhật những giá trị này?
  • Nếu tôi đã thêm một lịch trình, giả sử, 1 phút trong tương lai, điều đó có nghĩa là công việc sẽ không chạy kể từ khi next_run_date / time chưa được cập nhật?

Ví dụ về mã tôi sử dụng để thêm lịch biểu mới:

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

trong đó @jobID là nhị phân (16) chứa job_id của công việc đang đề cập, @ScheduleRunDate và @ScheduleRunTime là INT với ngày và giờ tương ứng.


3
Nó được cập nhật thông qua một công việc SQL Agent. Được cập nhật thông qua một công việc SQL Agent. Đệ quy đoàn kết!
Aaron Bertrand

1
Lời xin lỗi. Không có cơ hội để quay lại trong một thời gian.
BBlake

Câu trả lời:


16

Câu trả lời ngắn

Dường như dữ liệu trong msdb.dbo.sysjobschedulesđược cập nhật bởi một luồng nền trong Tác nhân SQL, được xác định là SQLAgent - Schedule Saver, cứ sau 20 phút (hoặc ít thường xuyên hơn, nếu xp_sqlagent_notifykhông được gọi và không có công việc nào chạy trong thời gian đó).

Để biết thông tin chính xác hơn, nhìn next_scheduled_run_datevào msdb.dbo.sysjobactivity. Điều này được cập nhật trong thời gian thực bất cứ khi nào một công việc được thay đổi hoặc một công việc đã chạy. Là một phần thưởng bổ sung, sysjobactivitylưu trữ dữ liệu đúng cách (dưới dạng cột thời gian), giúp công việc trở nên dễ dàng hơn rất nhiều so với các INT ngu ngốc đó.

Đó là câu trả lời ngắn gọn:

Nó có thể lên đến 20 phút trước khi sysjobschedules phản ánh sự thật; tuy nhiên, sysjobactivity sẽ luôn được cập nhật. Nếu bạn muốn biết thêm chi tiết về điều này, hoặc cách tôi tìm ra nó ...


Câu trả lời dài

Nếu bạn quan tâm theo dõi con thỏ một lúc, khi bạn gọi sp_add_jobschedule, chuỗi sự kiện này được thiết lập thành chuyển động:

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

Bây giờ, chúng ta không thể đuổi theo con thỏ nữa, vì chúng ta không thể nhìn trộm những gì xp_sqlagent_notifynó làm. Nhưng tôi nghĩ rằng chúng ta có thể đoán rằng quy trình mở rộng này tương tác với dịch vụ Đại lý và nói với nó rằng đã có một sự thay đổi đối với công việc và lịch trình cụ thể này. Bằng cách chạy theo dõi phía máy chủ, chúng ta có thể thấy rằng, ngay lập tức, SQL động sau đây được gọi bởi Tác nhân 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'

Có vẻ như nó sysjobactivityđược cập nhật ngay lập tức, và sysjobscheduleschỉ được cập nhật theo lịch trình. Nếu chúng tôi thay đổi lịch trình mới mỗi ngày một lần, vd

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

Chúng tôi vẫn thấy cập nhật ngay lập tức sysjobactivitynhư trên, và sau đó cập nhật khác sau khi công việc kết thúc. Các bản cập nhật khác nhau đến từ nền và các luồng khác trong SQL Agent, ví dụ:

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

Một luồng nền (luồng "Trình tiết kiệm lịch biểu") cuối cùng cũng xuất hiện và cập nhật sysjobschedules; từ cuộc điều tra ban đầu của tôi, có vẻ như cứ sau 20 phút, và chỉ xảy ra nếu xp_sqlagent_notifyđược gọi do thay đổi công việc kể từ lần cuối cùng chạy (Tôi không thực hiện bất kỳ thử nghiệm nào nữa để xem điều gì xảy ra nếu một công việc đã xảy ra đã thay đổi và một cái khác đã được chạy, nếu luồng "Lịch trình tiết kiệm" cập nhật cả hai - tôi nghi ngờ nó phải, nhưng sẽ để nó như một bài tập cho người đọc).

Tôi không chắc liệu chu kỳ 20 phút có được bù từ khi SQL Agent bắt đầu hay từ nửa đêm hoặc từ một thứ gì đó dành riêng cho máy không. Trên hai phiên bản khác nhau trên cùng một máy chủ vật lý, luồng "Lịch trình tiết kiệm" được cập nhật sysjobschedules, trên cả hai trường hợp, gần như cùng một lúc - 18:31:37 & 18:51:37 trên một, và 18:31:39 & 18:51:39 mặt khác. Tôi đã không khởi động SQL Server Agent cùng một lúc trên các máy chủ này, nhưng có khả năng từ xa là thời gian bắt đầu xảy ra là bù 20 phút. Tôi nghi ngờ điều đó, nhưng tôi không có thời gian để xác nhận bằng cách khởi động lại Đại lý trên một trong số họ và chờ đợi thêm thông tin cập nhật.

Tôi biết ai đã làm điều đó và khi nó xảy ra, bởi vì tôi đã đặt một bộ kích hoạt ở đó và bắt nó, trong trường hợp tôi không thể tìm thấy nó trong dấu vết, hoặc tôi vô tình lọc nó ra.

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

Điều đó nói rằng, không khó để bắt gặp với một dấu vết tiêu chuẩn, điều này thậm chí còn xuất hiện dưới dạng DML không động:

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

Nếu bạn muốn chạy một dấu vết được lọc nhiều hơn để theo dõi hành vi này theo thời gian (ví dụ: vẫn tồn tại thông qua khởi động lại Tác nhân SQL thay vì theo yêu cầu), bạn có thể chạy một dấu vết có appname = 'SQLAgent - Schedule Saver'...

Vì vậy, tôi nghĩ rằng nếu bạn muốn biết thời gian chạy tiếp theo ngay lập tức, hãy nhìn vào sysjobactivity, không sysjobschedules. Bảng này được Đại lý hoặc chủ đề nền của nó cập nhật trực tiếp ("Cập nhật hoạt động công việc", "Trình quản lý công việc" và "Công cụ gọi công việc") khi hoạt động xảy ra hoặc như được thông báo bởi xp_sqlagent_notify.

Mặc dù vậy, hãy lưu ý rằng rất dễ dàng để lấy một trong hai bảng - vì không có sự bảo vệ nào chống lại việc xóa dữ liệu khỏi các bảng này. (Vì vậy, nếu bạn quyết định dọn dẹp, chẳng hạn, bạn có thể dễ dàng xóa tất cả các hàng cho công việc đó khỏi bảng hoạt động.) Trong trường hợp này tôi không chắc chắn chính xác cách SQL Server Agent nhận hoặc lưu ngày chạy tiếp theo. Có lẽ xứng đáng để điều tra nhiều hơn vào một ngày sau đó khi tôi có thời gian rảnh ...


Nếu một công việc chưa chạy lần đầu tiên, sysjobschedules sẽ (cuối cùng) hiển thị các giá trị chính xác cho next_run_date và next_run_time, trong khi sysjobactivity.next_schediated_run_date vẫn không có giá trị cho đến sau lần thực hiện đầu tiên. Khi nhận được giá trị từ sysjobactivity, bạn cần thực hiện điều đó trong một truy vấn con nhóm theo job_id và nhận MAX (next_schediated_run_date).
Đánh dấu Freeman

0

msdb.dbo.sp_help_jobluôn luôn xuất hiện để trả về đúng thực tế next_run_date/ next_run_time.

Nó sử dụng sp_get_composite_job_info, thực hiện cuộc gọi sau để thực sự lấy 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

sysjobscheduledường như không đáng tin cậy, tôi sẽ chỉ sử dụng sp_help_job.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.