Write for Us
After the select statement runs, we have a global temporary table containing a list of indexes to update. It's important that the table have global scope, because the controller job is going to need to share it with the worker jobs actually performing the updates. Next, I "wrap" this select with some other code to control how long this process is allowed to run, and to start and stop our "worker" jobs, and put the code into a SQL Agent job:
declare @starttime datetime;set @starttime = getdate();
-- Number of minutes to continue updating stats-- Routine will complete its current operation and exit-- if more than this timespan has elapsed:declare @maxDur decimal (5,2);set @maxdur = 480;
print 'Updating statistics in ' + DB_NAME();print '';
set nocount on;
-- Make the queue of indexes to update:
if object_id('tempdb..##updateStatsQueue') is not null drop table ##updateStatsQueue;
select schemas.name as table_schema,tbls.name as table_name, i.name as index_name, i.id as table_id, i.indid as index_id,i.groupid,i.rowmodctr as modifiedRows,(select max(rowcnt) from sysindexes i2 where i.id = i2.id and i2.indid < 2) as rowcnt,stats_date( i.id, i.indid ) as lastStatsUpdate,'False' as Processedinto ##updateStatsQueuefrom sysindexes iinner join sysobjects tbls on i.id = tbls.idinner join sysusers schemas on tbls.uid = schemas.uidinner join information_schema.tables tl on tbls.name = tl.table_name and schemas.name = tl.table_schemaand tl.table_type='BASE TABLE'where 0 < i.indid and i.indid < 255and table_schema <> 'sys'and i.rowmodctr <> 0and (select max(rowcnt) from sysindexes i2 where i.id = i2.id and i2.indid < 2) > 0;-- Start worker jobs to process the queue
print 'Starting worker jobs';
-- Change the job names below as needed for implementation:exec msdb..sp_start_job @job_name = 'Update Stats Worker 1';exec msdb..sp_start_job @job_name = 'Update Stats Worker 2';exec msdb..sp_start_job @job_name = 'Update Stats Worker 3';exec msdb..sp_start_job @job_name = 'Update Stats Worker 4';
-- Monitor the queue; remove its temp table and exit once the entire table -- has been processed or the max duration has elapsed:
while ( datediff( minute, @starttime, getdate() ) < @maxdur and exists( select 1 from ##updateStatsQueue where processed = 'False' ) )begin-- Pause while worker jobs update statsprint 'Working ' + cast( getdate() as varchar(50) );waitfor delay '000:02:00';end
drop table ##updateStatsQueue;
print '';print 'Statistics update stopped/ended ' + cast( getdate() as varchar(50) );
This will create the queue as a global temp table, then start four other jobs that will perform the work. When either the maximum duration has elapsed or the workers have processed the whole queue, it will drop the temp table, which will cause the worker jobs to stop and exit.