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)
首先,我建议您使用免费脚本/工具之一来管理索引重建。最著名的之一是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 的脚本来实现它,以确保该过程不会运行太长时间。