如果时间太长,想要超时或跳过 SQL Server 索引重建语句

clo*_*afe 4 index sql-server sql-server-2012

在大型和高度碎片化的数据库上过夜运行索引重建脚本时,我们经常遇到停止工作的索引,因为它们似乎从未完成重建。作业暂停,早上我们必须手动取消语句,永远等待回滚,导致停机。我们可以修复这些偶尔手动删除和重新创建的索引。

如果没有什么进展,有没有办法自动使索引重建语句超时,以便脚本可以继续执行下一个重建语句?

我们的脚本是这样的:

ALTER INDEX ALL ON [Table1] REBUILD WITH (FILLFACTOR = 90)
ALTER INDEX ALL ON [Table2] REBUILD WITH (FILLFACTOR = 90)
ALTER INDEX ALL ON [Table3] REBUILD WITH (FILLFACTOR = 90)..
Run Code Online (Sandbox Code Playgroud)

RDF*_*ozz 5

首先,我建议您使用免费脚本/工具之一来管理索引重建。最著名的之一是Ola Hallengren 的数据库维护套件。这使您可以在尝试重新组织或重建索引之前控制它的碎片化程度。

其次 - 如果您仍然遇到进程似乎挂起的问题,请尝试创建两个作业。第一项工作实际上会运行索引重建过程。第二个作业将确保第一个作业的运行时间不会超过必要的时间。

我们将第一个作业称为“索引维护作业”。不要安排这项工作。

第二个作业将安排在您希望运行索引维护的时间,并执行以下脚本:

DECLARE @jobname nvarchar(128) = N'Index Maint Job';
DECLARE @proc_start_date datetime = GETDATE();

EXECUTE sp_start_job @job_name = @jobname;

WAITFOR DELAY '003:00:00';


IF (EXISTS (SELECT 1
              FROM sysjobactivity ja
                     INNER JOIN sysjobs j ON (ja.job_id = j.job_id)
             WHERE j.name = @jobname
               AND start_execution_date >= @proc_start_date
               AND stop_execution_date IS NULL
           )
   )
BEGIN
    Print N'Aborting job ''' + @jobname + N'''...';
    EXECUTE sp_stop_job @job_name = @jobname;
END
ELSE PRINT N'Job ''' + @jobname + N''' finished.';
Run Code Online (Sandbox Code Playgroud)

这将启动作业,等待您认为足够的时间完成它,检查它是否仍在运行,如果是,则停止它。

(我最初计划使用它TRY ... CATCH来捕获如果作业未运行而您尝试停止它时得到的错误;但是,这是一个TRY ... CATCH无法处理的 SQL Server 代理错误。因此,我们检查是否作业仍在运行。)

这里要知道的关键要素是sp_start_job不等待作业完成;一旦工作开始,它就会返回。因此,此时此作业将再次控制自己,并且可以等待您喜欢的任何时间(当前设置 [ WAITFOR DELAY '003:00:00'] 是三个小时)以查看作业是否仍在运行,如果是,则停止它。

仅供参考:正如其他人所指出的,索引重组是逐渐发生的;我有一个很大的碎片 PK 索引来尝试进行碎片整理,并计划使用 Ola 的脚本来实现它,以确保该过程不会运行太长时间。